La solución indicada por @ (Ted Hopp) funciona, pero necesita una pequeña corrección: en el selector, los estados del elemento necesitan un prefijo "app:", de lo contrario el inflador no reconocerá el espacio de nombres correctamente y fallará en silencio; Al menos esto es lo que me pasa.
Permítame informar aquí la solución completa, con algunos detalles más:
Primero, cree el archivo "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>
Luego defina su clase personalizada. Por ejemplo, puede ser una clase "FoodButton", derivada de la clase "Button". Tendrás que implementar un constructor; implementar este, que parece ser el utilizado por el inflador:
public FoodButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
En la parte superior de la clase derivada:
private static final int[] STATE_FRIED = {R.attr.state_fried};
private static final int[] STATE_BAKED = {R.attr.state_baked};
Además, sus variables de estado:
private boolean mIsFried = false;
private boolean mIsBaked = false;
Y un par de setters:
public void setFried(boolean isFried) {mIsFried = isFried;}
public void setBaked(boolean isBaked) {mIsBaked = isBaked;}
Luego anule la función "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;
}
Finalmente, la pieza más delicada de este rompecabezas; el selector que define el StateListDrawable que usará como fondo para su widget. Este es el archivo "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>
Observe el prefijo "app:", mientras que con los estados estándar de Android, habría utilizado el prefijo "android:". El espacio de nombres XML es crucial para que el inflador interprete correctamente y depende del tipo de proyecto en el que esté agregando atributos. Si es una aplicación, reemplace com.mydomain.mypackage con el nombre real del paquete de su aplicación (excluido el nombre de la aplicación). Si se trata de una biblioteca, debe usar "http://schemas.android.com/apk/res-auto" (y usar las Herramientas R17 o posterior) o obtendrá errores de tiempo de ejecución.
Un par de notas:
Parece que no necesita llamar a la función "refreshDrawableState", al menos la solución funciona bien como es, en mi caso
Para utilizar su clase personalizada en un archivo xml de diseño, deberá especificar el nombre completo (por ejemplo, com.mydomain.mypackage.FoodButton)
Puede combinar estados estándar (p. Ej., Android: presionado, android: habilitado, android: seleccionado) con estados personalizados, para representar combinaciones de estados más complicadas