android - medium - preferencefragmentcompat example
Cómo usar support.v7.preference con AppCompat y posibles inconvenientes (2)
Estaba tratando de implementar preferencias para una aplicación AppCompat, usando support.v7.preference. Me tomó un par de días repasarlo, ya que support.v7.preference tiene algunas diferencias significativas con respecto a las preferencias nativas ... lo cual no es tan malo una vez que lo sabes, pero desafortunadamente hay poca documentación. Pensé que compartiría mis conclusiones para que otros no tengan que pasar por el mismo dolor.
Entonces ... pregunta:
¿Cuál es la mejor forma de implementar las Preferencias para las aplicaciones de AppCompat (con PreferenceFragment y AppCompatAcitivity que son incompatibles)?
Aquí hay un par de preguntas relacionadas:
- La subpantalla de preferencias no se abre cuando se usa support.v7.preference
- ¿Cómo retroceder de la subpantalla de Preferencias a la pantalla principal en PreferenceFragmentCompat?
- PreferenceFragmentCompat requiere que se establezca preferencesTheme
- ¿Cómo creo preferencias personalizadas utilizando la biblioteca android.support.v7.preference?
Documentos oficiales aquí:
Solución 1: AppCompatActivity
PreferenceFragment
nativas con AppCompatActivity
En AndroidStudio, elija Archivo> Nuevo proyecto> ...> ConfiguraciónActividad . Esta plantilla usa una solución alternativa que actualiza el PreferenceFragment
nativo para que funcione con AppCompatActivity
, similar al support.v4.Fragment
o el support.v7.PreferenceFragmentCompat
.
- Pro: ahora puede usar la funcionalidad de preferencia nativa dentro de una aplicación
AppCompat
. Es un enfoque rápido cuando se utiliza la plantilla AS, y puede atenerse a los documentos y flujos de trabajo de Preferencias existentes. - Contras: la remodelación no es muy intuitiva o limpia. Además, dado que generalmente es recomendable usar bibliotecas de soporte cuando estén disponibles, no estoy seguro de qué tan a prueba de futuro es este enfoque.
Solución 2: support.v7.preference.PreferenceFragmentCompat
with AppCompatActivity
- Pro: maximiza la compatibilidad
- Con: un montón de huecos para salvar. Además, esto podría no funcionar con ninguna de las
FontPreferences
extensiones de preferencias existentes (por ejemplo,ColorPicker
oFontPreferences
).
Si decide no utilizar la Solución 1 (todavía no estoy seguro de cuál de los dos es más una prueba de futuro), hay un par de inconvenientes al usar support.v7.preference
.
Los inconvenientes importantes de usar la Solución 2 se mencionan a continuación.
Dependencias:
dependencies {
...
compile ''com.android.support:appcompat-v7:23.1.1''
compile ''com.android.support:preference-v7:23.1.1''
compile ''com.android.support:support-v4:23.1.1''
}
Tema: deberá definir un Tema de preferenceTheme
en su styles.xml, de lo contrario, ejecutar su aplicación generará una excepción.
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light">
<!-- Customize your theme here. -->
<item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>
Es posible que desee dividir esto en diferentes estilos para 7 + / 14 + / 21 +. Mucha gente se queja de que este esté lleno de errores al momento de escribir este artículo. Hay una respuesta muy completa disponible here .
Cambios de comportamiento: usar las preferencias nativas es extremadamente sencillo: todo lo que necesita hacer es definir / mantener sus preferences.xml
y usar addPreferencesFromResource(R.xml.preferences)
dentro de PreferenceFragment
. Las preferencias personalizadas se realizan fácilmente mediante la sub-clasificación de DialogPreference
, y luego se hace referencia a ellas dentro del preferences.xml
... bam, funciona.
Desafortunadamente, support.v7.preference
ha eliminado todo lo relacionado con tratar con Fragment
, lo que hace que pierda gran parte de su funcionalidad incorporada. En lugar de solo mantener un XML, ahora tienes que subclasificar y anular muchas cosas, todas las cuales desafortunadamente no están documentadas.
PreferenceScreens: PreferenceScreens
ya no es administrado por el marco. La definición de una PreferenceScreen
en su preference.xml
(como se describe en los docs ) mostrará la entrada, pero hacer clic en ella no hace nada. Ahora depende de usted ocuparse de visualizar y navegar por las subpantallas. Aburrido.
Hay un enfoque (descrito here ), que agrega un PreferenceFragmentCompat.OnPreferenceStartScreenCallback
a su PreferenceFragmentCompat
. Si bien este enfoque se implementa rápidamente, simplemente intercambia el contenido del fragmento de preferencia existente. El inconveniente es que no hay navegación hacia atrás, siempre estás ''arriba'', lo que no es muy intuitivo para el usuario.
En otro enfoque (que se describe here ), también deberá administrar la pila trasera para lograr la navegación trasera como se esperaba. Esto utiliza preferenceScreen.getKey()
como raíz para cada fragmento creado / mostrado recientemente.
Al hacerlo, también puede tropezar con que los PreferenceFragments
sean transparentes de forma predeterminada y se sumen de forma extraña uno encima del otro. Las personas tienden a anular PreferenceFragmentCompat.onViewCreated()
para agregar algo como
// Set the default white background in the view so as to avoid transparency
view.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.background_material_light));
Custom DialogPreference: Hacer tus propias preferencias también ha pasado de ser trivial a aburrido. DialogPreference
ahora tiene todo lo relacionado con el diálogo real, eliminado. Ese bit ahora vive en PreferenceDialogFragmentCompat
. Así que tendrás que sub-clasificar ambas, luego lidiar con la creación del diálogo y mostrarlo tú mismo (se explica here ).
Mirando la fuente de PreferenceFragmentCompat.onDisplayPreferenceDialog()
muestra que sabe cómo tratar exactamente con 2 preferencias de diálogo ( EditTextPreference
, ListPreference
), todo lo demás que tendrá que implementar usted mismo utilizando OnPreferenceDisplayDialogCallback
s ... uno se pregunta por qué no hay Funcionalidad para manejar la subclase de DialogPreference
!
Aquí hay un código que implementa la mayoría de estas soluciones y las encuadra en un módulo lib:
https://github.com/mstummer/extended-preferences-compat.git
Las principales intenciones fueron:
- Elimine la necesidad de ampliar y jugar con
Activity
yPreferenceFragment
en cada aplicación / proyecto.preference.xml
es ahora nuevamente el único archivo por proyecto para cambiar / mantener. - Manejar y mostrar
PreferenceScreens
(pantallas secundarias) como se esperaba. - Anule la división de
DialogPreference
para restaurar el comportamiento nativo. - Manejar y mostrar cualquier subclase de
DialogPreference
.
No piense que está lo suficientemente limpio como para usarlo de inmediato, pero podría darle algunos consejos cuando trate con problemas similares. Dale una vuelta y déjame saber si tienes alguna sugerencia.
Tengo una solución alternativa a esta, de la que me encantaría recibir comentarios.
Hice un diseño personalizado para mi fragmento de preferencia, con un botón "Atrás" en la esquina superior izquierda.
Primero, en el "onCreatePreference" guardo la PreferenceScreen raíz:
root = this.getPreferenceScreen();
Luego, agrego el OnPreferenceStartScreenCallback como se describe anteriormente y en otros subprocesos para hacer que el fragmento pase a la subpantalla, pero en mi "onPreferenceStartScreen" también configuro el botón de retroceso para que se vea de esta manera:
public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, PreferenceScreen preferenceScreen) {
preferenceFragmentCompat.setPreferenceScreen(preferenceScreen);
backButton.setVisibility(View.VISIBLE);
return true;
}
Finalmente, el backButton clickhandler:
setPreferenceScreen(root);
back.setVisibility(View.GONE);
Esto parece funcionar bien para mí. Obviamente, la pila trasera no funcionará, pero puedo vivir con eso ya que hay un botón Atrás.
No es perfecto, pero dada la API abismal creo que estoy feliz.
Me encantaría escuchar si alguien piensa que hay algún problema con este enfoque.