PreferenceInternet no se abre con PreferenceFragmentCompat
Mi PreferenceScreen interno de PreferenceFragmentCompat no está mostrando, o parece ignorar los eventos de tapping.
He creado MyPreferenceFragment
que extends PreferenceFragmentCompat
- Android: RecyclerView dentro de un ScrollView (o paralaje)
- getActionBar no funciona con AppCompat lib
- El menú emergente desaparece de la pantalla
- No se puede cambiar el tema Appcompat de luz a holo oscuro
- Obtener ActionBar Título TextView con AppCompat v7 r21
public class MyPreferenceFragment extends PreferenceFragmentCompat { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences); } }
entonces cambié mi tema en styles.xml
como
<style name="AppTheme" parent="@style/Theme.AppCompat.Light"> <item name="preferenceTheme">@style/PreferenceThemeOverlay</item> </style>
Y finalmente crear mi archivo preferences.xml
como
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <CheckBoxPreference android:title="Check Me"/> <PreferenceScreen android:title="My Screen"> <!-- This is not opening --> <EditTextPreference android:title="Edit text" /> </PreferenceScreen> </PreferenceScreen>
En el build.gradle
he añadido ambos:
compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.android.support:preference-v7:23.0.1'
código de la actividad
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
activity_main.xml
<fragment xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment" android:name="com.mando.preferenceapp.MyPreferenceFragment" android:layout_width="match_parent" android:layout_height="match_parent" />
Prueba del código anterior No puedo abrir / entrar en la pantalla de preferencias. ¿Me estoy perdiendo de algo? ¿Por qué esto no funciona?
- Menú de desbordamiento textColor con AppCompat (usando la tecla de menú de hardware)
- Barra de herramientas de AppCompat v7 onOptionsItemSelected no llamado
- CoordinatorLayout con RecyclerView & CollapsingToolbarLayout
- Barra de herramientas flotante con Appcompat
- ¿Necesito AppCompatActivity y v7 Support Bibliotecas con mínimo sdk 21?
- AppCompatButton backgroundTint API <21
- Problema con Android app-v7-appcompat con 4.0 y superior
- OnPrepareOptionsMenu en Fragmento no se llama como de AppCompat v22 (API 10)
Después de pasar muchas horas con intentos, buscando y agradecidamente con alguna ayuda de los creadores de la biblioteca de apoyo. He conseguido que funcione.
Paso 1. Activity
public class MyActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartScreenCallback { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { // Create the fragment only when the activity is created for the first time. // ie. not after orientation changes Fragment fragment = getSupportFragmentManager().findFragmentByTag(MyPreferenceFragment.FRAGMENT_TAG); if (fragment == null) { fragment = new MyPreferenceFragment(); } FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.fragment_container, fragment, MyPreferenceFragment.FRAGMENT_TAG); ft.commit(); } } @Override public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, PreferenceScreen preferenceScreen) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); MyPreferenceFragment fragment = new MyPreferenceFragment(); Bundle args = new Bundle(); args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, preferenceScreen.getKey()); fragment.setArguments(args); ft.replace(R.id.fragment_container, fragment, preferenceScreen.getKey()); ft.addToBackStack(preferenceScreen.getKey()); ft.commit(); return true; } }
Consejos.
- No agregue el fragmento por
xml
, tendrá fallos en los cambios de orientación. - Manejar las recreaciones de actividad / fragmento agregar en
onCreate
para evitar perder su fragmento cuando está dentro de una pantalla de preferencias. - La actividad de host del fragmento debe implementar el
PreferenceFragmentCompat.OnPreferenceStartScreenCallback
y volver a crear fragmentos de la misma instancia.
Paso 2. PreferenceFragment
public class MyPreferenceFragment extends PreferenceFragmentCompat { public static final String FRAGMENT_TAG = "my_preference_fragment"; public MyPreferenceFragment() { } @Override public void onCreatePreferences(Bundle bundle, String rootKey) { setPreferencesFromResource(R.xml.preferences, rootKey); } }
Consejos.
- Utilice el método
setPreferencesFromResource
y aproveche larootKey
de cada pantalla. De esta manera su código se reutilizará correctamente. - Tenga en cuenta que si tiene código como
findPreference
en su fragmento debe tener controlesnull
como cuando estaba en pantallas internas esto no le dará nada.
Lo que falta ahora es la implementación de la flecha hacia atrás en la barra de acción (acción de casa) pero esto nunca funciona por sí mismo 😉
También he creado una aplicación demo que envuelve todo este código que puedes encontrar en github .
Lo hice de manera ligeramente diferente, estoy lanzando una nueva actividad para cada pantalla. Esto parece requerir menos hacks: no hay necesidad de meterse con el intercambio de fragmentos y colores de fondo. Usted también consigue animación de cambio de actividad como un bono!
public class PreferencesActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartScreenCallback { final static private String KEY = "key"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.preferences); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) actionBar.setDisplayHomeAsUpEnabled(true); if (savedInstanceState != null) return; Fragment p = new PreferencesFragment(); String key = getIntent().getStringExtra(KEY); if (key != null) { Bundle args = new Bundle(); args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, key); p.setArguments(args); } getSupportFragmentManager().beginTransaction() .add(R.id.preferences, p, null) .commit(); } @Override public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, PreferenceScreen preferenceScreen) { Intent intent = new Intent(PreferencesActivity.this, PreferencesActivity.class); intent.putExtra(KEY, preferenceScreen.getKey()); startActivity(intent); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { onBackPressed(); return true; } return super.onOptionsItemSelected(item); } public static class PreferencesFragment extends PreferenceFragmentCompat implements ... { private static final String FRAGMENT_DIALOG_TAG = "android.support.v7.preference.PreferenceFragment.DIALOG"; private String key; @Override public void onCreatePreferences(Bundle bundle, String key) { setPreferencesFromResource(R.xml.preferences, this.key = key); } // this only sets the title of the action bar @Override public void onActivityCreated(Bundle savedInstanceState) { ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); if (actionBar != null) actionBar.setTitle((key == null) ? "Settings" : findPreference(key).getTitle()); super.onActivityCreated(savedInstanceState); } } }
xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="0dp" android:orientation="vertical" android:padding="0dp" android:id="@+id/preferences"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" /> <!-- preference fragment will be inserted here programmatically --> </LinearLayout>
Basado en la solución @squirrel Intent, lo hice funcionar de esta manera. Requiere aún menos hacking.
Actividad:
import android.support.v7.app.AppCompatActivity; public class SettingsActivity extends AppCompatActivity { public static final String TARGET_SETTING_PAGE = "target"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SettingsFragment settingsFragment = new SettingsFragment(); Intent intent = getIntent(); if (intent != null) { String rootKey = intent.getStringExtra(TARGET_SETTING_PAGE); if (rootKey != null) { settingsFragment.setArguments(Bundler.single(TARGET_SETTING_PAGE, rootKey)); } } getFragmentManager().beginTransaction() .replace(android.R.id.content, settingsFragment) .commit(); } }
Fragmento:
import android.support.v14.preference.PreferenceFragment; public class SettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle arguments = getArguments(); if (arguments != null && arguments.getString(TARGET_SETTING_PAGE) != null) { setPreferencesFromResource(R.xml.preferences, arguments.getString(TARGET_SETTING_PAGE)); } else { addPreferencesFromResource(R.xml.preferences); } } @Override public void onNavigateToScreen(PreferenceScreen preferenceScreen) { Intent intent = new Intent(getActivity(), SettingsActivity.class) .putExtra(TARGET_SETTING_PAGE, preferenceScreen.getKey()); startActivity(intent); super.onNavigateToScreen(preferenceScreen); } }
Es triste que necesites tantos hacks en las librerías appcompat de soporte para algo que funcione perfectamente out-of-the-box en android estándar.