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
- El botón de acción flotante no es visible al desplazarse después de actualizar Google Support & Design Library
- El logotipo no se muestra en la barra de acciones, con AppCompat
- app: el tema ahora está obsoleto
- ¿Cómo escuchar el cambio de estado en el widget SwitchCompat?
- Junit.framework.AssertionFailedError: Excepción en constructor: (java.lang.NoClassDefFoundError)
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?
- LayoutInflater de la actividad ya tiene instalado un Factory para que no podamos instalar AppCompat
- Appcompat "java.lang.IllegalArgumentException: el parámetro debe ser un descendiente de esta vista" en ViewGroup.offsetRectBetweenParentAndChild
- ¿Debo usar AppCompat v7 si minsdk es 14
- Cómo mostrar los elementos de acción en la parte inferior mediante la barra de herramientas
- ¿Cuándo se encuentra la barra de progreso indeterminada en Android Support Library
- Cómo ocultar el indicador del cajón de navegación mientras utiliza appcompat21
- Android FloatingActionButton de repente es transparente sólo en la generación de ProGuard
- La vista de búsqueda no funciona desde la aplicación compat
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.