La solution indiquée par @ (Ted Hopp) fonctionne, mais nécessite une petite correction: dans le sélecteur, les états de l'élément ont besoin d'un préfixe "app:", sinon le gonfleur ne reconnaîtra pas correctement l'espace de noms, et échouera silencieusement; du moins c'est ce qui m'arrive.
Permettez-moi de vous rapporter ici toute la solution, avec quelques détails supplémentaires:
Commencez par créer le fichier "res / values / attrs.xml":
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="food">
<attr name="state_fried" format="boolean" />
<attr name="state_baked" format="boolean" />
</declare-styleable>
</resources>
Définissez ensuite votre classe personnalisée. Par exemple, il peut s'agir d'une classe "FoodButton", dérivée de la classe "Button". Vous devrez implémenter un constructeur; implémentez celui-ci, qui semble être celui utilisé par le gonfleur:
public FoodButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
En plus de la classe dérivée:
private static final int[] STATE_FRIED = {R.attr.state_fried};
private static final int[] STATE_BAKED = {R.attr.state_baked};
En outre, vos variables d'état:
private boolean mIsFried = false;
private boolean mIsBaked = false;
Et quelques setters:
public void setFried(boolean isFried) {mIsFried = isFried;}
public void setBaked(boolean isBaked) {mIsBaked = isBaked;}
Remplacez ensuite la fonction "onCreateDrawableState":
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 2);
if (mIsFried) {
mergeDrawableStates(drawableState, STATE_FRIED);
}
if (mIsBaked) {
mergeDrawableStates(drawableState, STATE_BAKED);
}
return drawableState;
}
Enfin, la pièce la plus délicate de ce puzzle; le sélecteur définissant le StateListDrawable que vous utiliserez comme arrière-plan de votre widget. Il s'agit du fichier "res / drawable / food_button.xml":
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.mydomain.mypackage">
<item
app:state_baked="true"
app:state_fried="false"
android:drawable="@drawable/item_baked" />
<item
app:state_baked="false"
app:state_fried="true"
android:drawable="@drawable/item_fried" />
<item
app:state_baked="true"
app:state_fried="true"
android:drawable="@drawable/item_overcooked" />
<item
app:state_baked="false"
app:state_fried="false"
android:drawable="@drawable/item_raw" />
</selector>
Notez le préfixe "app:", alors qu'avec les états Android standard, vous auriez utilisé le préfixe "android:". L'espace de noms XML est crucial pour une interprétation correcte par le gonfleur et dépend du type de projet dans lequel vous ajoutez des attributs. S'il s'agit d'une application, remplacez com.mydomain.mypackage par le nom réel du package de votre application (nom de l'application exclu). S'il s'agit d'une bibliothèque, vous devez utiliser "http://schemas.android.com/apk/res-auto" (et utiliser Tools R17 ou version ultérieure) ou vous obtiendrez des erreurs d'exécution.
Quelques notes:
Il semble que vous n'ayez pas besoin d'appeler la fonction "refreshDrawableState", au moins la solution fonctionne bien telle quelle, dans mon cas
Afin d'utiliser votre classe personnalisée dans un fichier xml de mise en page, vous devrez spécifier le nom complet (par exemple com.mydomain.mypackage.FoodButton)
Vous pouvez comme weel mélanger des états standard (par exemple android: pressé, android: activé, android: sélectionné) avec des états personnalisés, afin de représenter des combinaisons d'états plus compliquées