java - textappearance - theme editor android studio
AplicaciĆ³n del tema de AppCompat a las preferencias individuales en un PreferenceFragment (4)
He estado luchando con intentar que mi PreferenceFragment
tenga el mismo tema y estilo basado en materiales (a través de AppCompat) que el resto de mi aplicación. El PreferenceFragment
que estoy usando para administrar todas las configuraciones de mi aplicación se muestra a continuación:
Como puede ver en la captura de pantalla anterior, pude personalizar el PreferenceFragment
mediante el uso de colorAccent
, colorPrimary
y algunos otros atributos. Mi tema para el PreferenceFragment
es el siguiente:
<style
name="settingsTheme"
parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/blue_grey_500</item>
<item name="colorAccent">@color/blue_grey_500</item>
<item name="android:textColor">@color/black_text_alt</item>
<item name="android:textColorSecondary">@color/black_secondary_text</item>
</style>
Sin embargo, a pesar de mis mejores esfuerzos, no puedo aplicar temas a los elementos individuales dentro de mi PreferenceFragment
, como ListPreference
y EditTextPreference
; Todas las preferencias aún conservan el tema estándar de AppCompat:
Encontré una publicación de 2 años que trata este tema, aunque sin una solución real: cómo aplicar el tema a los elementos <PreferenceScreen> de una <PreferenceCategory>
Me pregunto si alguien ha podido aplicar con éxito temas a las preferencias desde que se lanzó AppComat V21. Si no es así, ¿existen soluciones alternativas viables que puedan usarse para aplicar temas personalizados a las preferencias individuales?
Debería consultar esta Gist sobre cómo los diferentes componentes utilizan los atributos de color del tema. Es posible que deba agregar los siguientes atributos a su tema para obtener el efecto que desea:
<item name="colorControlNormal">@color/x_color</item>
<item name="colorControlActivated">@color/y_color</item>
<item name="colorControlHighlight">@color/z_color</item>
Tomando pistas de las respuestas ya dadas, establezco en el manifiesto un tema personalizado para la actividad de Configuración porque es necesario eliminar el fondo del borde alrededor del diálogo que aparece, utilizando un fondo transparente solo para API <21:
AndroidManifest.xml
<application
android:name=".MyApplication"
...
android:theme="@style/AppTheme">
...
<activity
android:name=".ui.SettingsActivity"
...
android:theme="@style/AppTheme.Settings">
</activity>
</application>
valores / estilo.xml
<!-- Application theme -->
<style name="AppTheme" parent="AppTheme.Base">
<!-- All customizations that are NOT specific to a particular API-level can go here. -->
</style>
<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
...
<item name="android:alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style>
<!-- Must be different because of transparent background -->
<style name="AppTheme.Settings" parent="AppTheme.Base">
<item name="android:alertDialogTheme">@style/AppTheme.SettingsAlertDialog</item>
</style>
<style name="AppTheme.AlertDialog" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
<item name="android:windowContentOverlay">@null</item>
<item name="colorAccent">@color/accent_light</item>
<item name="colorControlActivated">@color/accent_light</item>
<item name="colorControlHighlight">@color/primary_highlight</item>
</style>
<style name="AppTheme.SettingsAlertDialog" parent="Theme.AppCompat.Light.Dialog.Alert">
<item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="colorAccent">@color/accent_light</item>
<item name="colorControlActivated">@color/accent_light</item>
<item name="colorControlHighlight">@color/primary_highlight</item>
</style>
finalmente, para values- v21 /style.xml, el diálogo normal, si no lo coloca en v21, los diálogos serán transparentes.
<style name="AppTheme.Settings" parent="AppTheme.Base">
<item name="android:alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style>
En realidad, tengo el problema de establecer los colores directamente desde los atributos del tema:? Android: colorAccent en lugar de mi color fijo @ color / accent_light.
DialogPreference
utiliza android.app.AlertDialog.Builder
directamente, por lo que sería imposible cambiar el diálogo mostrado al diseño de material para todos los niveles de API (lo que requiere el uso de android.support.v7.widget.AlertDialog.Builder
).
Creo que la única opción por ahora es extender y anular la lógica de creación de diálogos en DialogPreference
o sus subclases (y usar la reflexión para DialogPreference
privados si es necesario). Echa un vistazo a este hilo reddit y un ejemplo AppCompatListPreference
realizado por el autor de ese hilo.
ACTUALIZACIÓN: hice una biblioteca para combatir el problema (usa AppCompat r22): https://github.com/consp1racy/android-support-preference
ListPreference
extiende DialogPreference
que utiliza este fragmento de código para crear el cuadro de diálogo:
mBuilder = new AlertDialog.Builder(context)
.setTitle(mDialogTitle)
.setIcon(mDialogIcon)
.setPositiveButton(mPositiveButtonText, this)
.setNegativeButton(mNegativeButtonText, this);
Como puede ver, el constructor AlertDialog.Builder
no se suministra con el segundo parámetro opcional de int theme
. Eso significa que el diálogo será temático según el tema de su actividad en su atributo android:alertDialogTheme
.
Ahora tiene que crear un tema personalizado para su cuadro de diálogo que se deriva de Theme.AppCompat.Dialog
así:
<style name="Theme.YourApp.Dialog.Alert" parent="Theme.AppCompat.Light.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
<item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
<item name="colorAccent">@color/accent_yourapp</item>
<item name="colorPrimary">@color/primary_yourapp</item>
<item name="colorPrimaryDark">@color/primary_dark_yourapp</item>
</style>
Problema 1: la solución anterior no funcionará para RingtonePreference
porque no extiende ListPreference
sino que llama a la intención de ListPreference
un tono de llamada, por lo que siempre tiene un tema según el sistema. Echa un vistazo a esta respuesta: Tema RingtonePreference Para que podamos marcar esto como resuelto.
Problema 2: Los cuadros de diálogo de AppCompat carecen de título. Y hasta ahora no he encontrado una manera de arreglar esto. Es cierto que no estoy mirando lo suficiente. Ignoremos la ausencia del título como un asunto menor.
Problema 3: los dibujables de los botones de radio no están mutados, por lo que los gráficos son inconsistentes entre el estado pasivo y activo (coloreado); todos son de color (no solo el que está presionando) o todos son de color gris. Ahora esto es realmente molesto
Los problemas 2 y 3 me obligaron a tomar otra ruta: el tema de mi diálogo se ve así en API 14+
<style name="Theme.MyApp.Dialog.Alert" parent="android:Theme.DeviceDefault.Light.Dialog.MinWidth">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
</style>
Y así en la API 21+
<style name="Theme.YourApp.Dialog.Alert" parent="android:Theme.DeviceDefault.Light.Dialog.MinWidth">
<item name="android:colorPrimary">@color/primary_yourapp</item>
<item name="android:colorPrimaryDark">@color/primary_dark_yourapp</item>
<item name="android:colorAccent">@color/accent_yourapp</item>
</style>
Estos valores se han obtenido experimentalmente mediante el rastreo a través de los archivos fuente de la plataforma y se han probado.
El punto es que la única solución confiable parece estar usando el tema de diálogo predeterminado del dispositivo. La única opción antes de Lollipop es una variante clara u oscura. En Lollipop esto funcionará según lo previsto y solicitado.
EDITAR: Desde appcompat-v7-r21.1.0 puede usar AppCompatDialog
que es una variante temática de material de AlertDialog
nativo.
Puede utilizar AlertDialog.Builder
proporcionado (no debe confundirse con su contraparte nativa) para crear sus instancias.