La solución indicada por @ (Ted Hopp) funciona, pero necesita una pequeña corrección: en el selector, la los estados de los elementos necesitan un prefijo "aplicación:"; de lo contrario, el inflador no reconocerá correctamente el espacio de nombres y fallará en silencio; al menos esto es lo que me sucede.
Permítame Presentamos aquí la solución completa, con algunos detalles más:
En primer lugar, crear el archivo "res/valores/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>
a continuación, definir la clase personalizada. Por ejemplo, puede ser una clase "FoodButton", derivada de la clase "Button". Tendrás que implementar un constructor; aplicar éste, que parece ser la utilizada por el inflado:
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;}
función Entonces anular "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;
}
Por último, la más delicada pieza de este rompecabezas; el selector que define StateListDrawable que usará como fondo para su widget. Se trata de "res/estirable/food_button.xml" file:
<?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>
Aviso de la "app:" prefijo, mientras que con los estados estándar de Android que habría utilizado prefijo "androide". El espacio de nombres XML es crucial para una interpretación correcta por parte del inflador y depende del tipo de proyecto en el que está agregando atributos. Si se trata de una aplicación, reemplace com.mydomain.mypackage con el nombre del paquete real de su aplicación (nombre de la aplicación excluido). Si se trata de una biblioteca, debe utilizar "http://schemas.android.com/apk/res-auto" (y usar Tools R17 o posterior) o obtendrá errores en tiempo de ejecución.
Un par de notas:
Parece que no es necesario llamar a la función "refreshDrawableState", al menos, la solución funciona bien como es, en mi caso
Con el fin para usar su clase personalizada en un archivo xml de diseño, deberá especificar el nombre completo (ej. com.mydomain.mypackage.FoodButton)
Usted puede como weel mix-up estados convencionales (por ejemplo android: presionado, Android: habilitada, android: seleccionado) con los estados personalizados, con el fin de representar más complicadas combinaciones de estados
Necesitaba estados adicionales para una vista de Editar texto para determinar cuándo coinciden dos casillas de contraseña para mostrar una pequeña marca de verificación. – schwiz