Je me suis efforcé d’essayer d’obtenir ma PreferenceFragment
afin d’avoir le même thème et le même style fondés sur des matériaux (via AppCompat) que le reste de ma candidature. La PreferenceFragment
que j'utilise pour gérer tous les paramètres de mon application est indiquée ci-dessous:
Comme vous pouvez le voir sur la capture d'écran ci-dessus, j'ai pu personnaliser PreferenceFragment
en utilisant colorAccent
, colorPrimary
et quelques autres attributs. Mon thème pour la PreferenceFragment
est le suivant:
<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>
Cependant, malgré tous mes efforts, je ne parviens pas à appliquer de thèmes aux éléments individuels de ma PreferenceFragment
, tels que ListPreference
et EditTextPreference
; toutes les préférences conservent toujours le thème standard AppCompat:
J'ai trouvé un article de 2 ans traitant de ce problème, mais sans réelle solution: Comment appliquer le thème à des éléments <PreferenceScreen> d'une <PreferenceCategory>
Je me demande si quelqu'un a réussi à appliquer des thèmes aux préférences depuis la sortie d'AppComat V21. Si ce n'est pas le cas, existe-t-il des solutions de contournement viables pouvant être utilisées pour appliquer des thèmes personnalisés à des préférences individuelles?
UPDATE: J'ai créé une bibliothèque pour résoudre le problème (utilise AppCompat r22): https://github.com/consp1racy/Android-support-preference
ListPreference
extend DialogPreference
qui utilise cette partie de code pour créer la boîte de dialogue:
mBuilder = new AlertDialog.Builder(context)
.setTitle(mDialogTitle)
.setIcon(mDialogIcon)
.setPositiveButton(mPositiveButtonText, this)
.setNegativeButton(mNegativeButtonText, this);
Comme vous pouvez le constater, le constructeur AlertDialog.Builder
n’est pas fourni avec le deuxième paramètre optionnel int theme
. Cela signifie que le dialogue sera thématisé par tout ce que le thème de votre activité a dans son attribut Android:alertDialogTheme
.
Vous devez maintenant créer un thème personnalisé pour votre boîte de dialogue, qui dérive de Theme.AppCompat.Dialog
comme suit:
<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>
Problème 1: La solution ci-dessus ne fonctionnera pas pour RingtonePreference
car elle n’étend pas ListPreference
mais appelle une intention de sélecteur de sonnerie, elle est donc toujours thématisée en fonction du système. Découvrez cette réponse: Thème RingtonePreference Nous pouvons donc marquer ceci comme résolu.
Problème 2: Les boîtes de dialogue AppCompat n'ont pas de titre. Et jusqu'à présent, je n'ai pas trouvé le moyen de résoudre ce problème. C'est vrai que je ne cherche pas assez fort. Ignorons l'absence de titre en tant que problème mineur.
Problème 3: Les boutons de la case d'option radio ne sont pas mutés, ainsi les graphiques ne sont pas cohérents entre l'état passif et actif (en couleur) - tous sont colorés (pas uniquement celui que vous appuyez) ou tous sont en gris. Maintenant c'est vraiment ennuyeux
Les problèmes 2 et 3 m'ont obligé à emprunter un autre chemin: mon thème de dialogue ressemble à ceci dans l'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>
et comme ça sur 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>
Ces valeurs ont été acquises expérimentalement en explorant les fichiers sources de la plate-forme et ont été bien testées.
Le fait est que la seule solution fiable semble utiliser le thème de dialogue par défaut du périphérique. Le seul choix avant Lollipop est une variante claire ou sombre. Sur Lollipop cela fonctionnera comme prévu et demandé.
EDIT: Depuis appcompat-v7-r21.1.0, vous pouvez utiliser AppCompatDialog
qui est une variante à thème matériel de la variable native AlertDialog
.
Vous pouvez utiliser le paramètre AlertDialog.Builder
fourni (à ne pas confondre avec son équivalent natif) pour créer ses instances.
DialogPreference
utilise Android.app.AlertDialog.Builder
directement, il serait donc impossible de basculer la boîte de dialogue affichée sur celle de conception des matériaux pour tous les niveaux d'API (ce qui nécessite d'utiliser Android.support.v7.widget.AlertDialog.Builder
).
Je crois que la seule option pour le moment est d'étendre et de remplacer la logique de création de dialogue dans DialogPreference
ou ses sous-classes (et d'utiliser la réflexion pour contourner les accesseurs privés si nécessaire). Découvrez ce fil reddit et un exemple AppCompatListPreference
créé par l'auteur de ce fil.
En me basant sur les réponses déjà données, j'ai défini dans le manifeste un thème personnalisé pour l'activité Paramètres, car il est nécessaire de supprimer l'arrière-plan de la bordure entourant la boîte de dialogue qui apparaît, en utilisant un arrière-plan transparent, ceci uniquement pour l'API <21:
AndroidManifest.xml
<application
Android:name=".MyApplication"
...
Android:theme="@style/AppTheme">
...
<activity
Android:name=".ui.SettingsActivity"
...
Android:theme="@style/AppTheme.Settings">
</activity>
</application>
values / style.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>
enfin pour values - v21 / style.xml le dialogue normal, si vous ne le mettez pas dans la v21, les dialogues seront transparents.
<style name="AppTheme.Settings" parent="AppTheme.Base">
<item name="Android:alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style>
En fait, j'ai le problème de définir les couleurs directement à partir des attributs de thème:? Android: colorAccent au lieu de ma couleur fixe @ color/accent_light.
Vous devriez consulter this Gist sur la manière dont différents composants utilisent les attributs de couleur de thème. Vous devrez peut-être ajouter les attributs suivants à votre thème pour obtenir l'effet souhaité:
<item name="colorControlNormal">@color/x_color</item>
<item name="colorControlActivated">@color/y_color</item>
<item name="colorControlHighlight">@color/z_color</item>