studio preferencefragmentcompat medium example custom create activity android appcompat android-preferences preferencescreen preference-v7

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:

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 o FontPreferences ).

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 y PreferenceFragment 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.