Je veux avoir 2 thèmes sélectionnables pour mon application. Pour ce faire, j'ai défini certains attributs, comme ceci:
<attr format="color" name="item_background" />
Ensuite, j'ai créé les deux thèmes, comme ceci:
<style name="ThemeA">
<item name="item_background">#123456</item>
</style>
<style name="ThemeB">
<item name="item_background">#ABCDEF</item>
</style>
Cette méthode fonctionne très bien, me permettant de créer et de modifier facilement plusieurs thèmes. Le problème est que il semble qu'il ne puisse être utilisé que dans les vues, et non dans Drawables.
Par exemple, référencer une valeur depuis une vue à l'intérieur d'une présentation fonctionne:
<TextView Android:background="?item_background" />
Mais faire la même chose dans Drawable ne:
<shape Android:shape="rectangle">
<solid Android:color="?item_background" />
</shape>
Je reçois cette erreur lors de l'exécution de l'application:
Java.lang.UnsupportedOperationException: Can't convert to color: type=0x2
Si, au lieu de ?item_background
, j'utilise une couleur codée en dur, cela fonctionne, mais cela ne me permet pas d'utiliser mes thèmes. J'ai aussi essayé ?attr:item_background
, mais la même chose se produit.
Comment pourrais-je faire ça? Et pourquoi cela fonctionne-t-il dans les vues mais pas dans Drawables? Je ne trouve cette limitation nulle part dans la documentation ...
D'après mon expérience, il n'est pas possible de référencer un attribut dans un dessin XML.
Pour créer votre thème, vous devez:
Incluez la couleur requise dans votre dessin directement avec la balise @color
ou le format #RGB.
Créez un attribut pour votre dessin dans attrs.xml .
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Attributes must be lowercase as we want to use them for drawables -->
<attr name="my_drawable" format="reference" />
</resources>
Ajoutez votre dessin à votre theme.xml .
<style name="MyTheme" parent="@Android:style/Theme.NoTitleBar">
<item name="my_drawable">@drawable/my_drawable</item>
</style>
Référencez votre dessin dans votre mise en page en utilisant votre attribut.
<TextView Android:background="?my_drawable" />
À partir de Lollipop
(API 21), cette fonctionnalité est prise en charge, voir https://code.google.com/p/Android/issues/detail?id=26251
Toutefois, si vous ciblez des appareils sans Lollipop, ne l'utilisez pas car cela planterait, utilisez plutôt la solution de contournement dans la réponse acceptée.
Bien qu'il soit impossible de référencer les attributs de style à partir de drawables sur les périphériques pré-Lollipop, il est toutefois possible d'utiliser des listes d'état de couleurs. Vous pouvez utiliser la méthode AppCompatResources.getColorStateList (contexte de contexte, intIID) } de la bibliothèque de support Android. L'inconvénient est que vous devrez définir ces listes d'état de couleur par programme.
Voici un exemple très basique.
color/my_color_state.xml
<selector xmlns:Android="http://schemas.Android.com/apk/res/Android">
<item Android:state_checked="true" Android:color="?colorControlActivated" />
<item Android:color="?colorControlNormal" />
</selector>
Un widget nécessitant une liste d'états de couleurs:
<RadioButton
Android:id="@+id/radio_button"
Android:text="My Radio" />
Et le plus important:
ColorStateList csl = AppCompatResources.getColorStateList(context, R.color.my_color_state);
RadioButton r = (RadioButton) findViewById(R.id.radio_button);
r.setTextColor(csl);
Eh bien, ce n’est pas le moyen le plus élégant ni le plus court, mais c’est ce que fait la bibliothèque de support Android pour le faire fonctionner sur les versions antérieures (pré-Lollipop) d’Android.
Malheureusement, la méthode similaire pour drawables ne fonctionne pas avec les attributs de style.
Comme @marmor l'a déclaré, cela est désormais pris en charge par l'API 21. Mais vous pouvez utiliser cette fonctionnalité pour ceux qui ont besoin de prendre en charge les versions antérieures d'Android. En utilisant la bibliothèque de support v7, vous pouvez toujours l’utiliser sur des applications avec un niveau de SDK minimal jusqu’à 7.
La AppCompatImageView
de la bibliothèque de support Android v7 a une implémentation sans bogue de cette fonctionnalité. Remplacez simplement vos utilisations de ImageView
par AppCompatImageView
.