Cómo agregar un estado de botón personalizado

Por ejemplo, el botón predeterminado tiene las siguientes dependencias entre sus estados e imágenes de fondo:

          

¿Cómo puedo definir mi propio estado personalizado (smth like android:state_custom ), entonces podría usarlo para cambiar dinámicamente la apariencia visual de mi botón?

    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 “aplicación:”; de lo contrario, el inflador no reconocerá correctamente el espacio de nombre y fallará en silencio; al menos esto es lo que me sucede.

    Permítanme informar aquí toda la solución, con algunos detalles más:

    Primero, crea el archivo “res / values ​​/ attrs.xml”:

     < ?xml version="1.0" encoding="utf-8"?>       

    Luego, define tu clase personalizada. Por ejemplo, puede ser una clase “FoodButton”, derivada de la clase “Button”. Tendrás que implementar un constructor; implementar esta, que parece ser la utilizada 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 StateListDrawable que usará como fondo para su widget. Este es el archivo “res / drawable / food_button.xml”:

     < ?xml version="1.0" encoding="utf-8"?>       

    Observe el prefijo “aplicación:”, mientras que con los estados androids estándar debería haber usado el prefijo “android:”. 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.midominio.mipackage 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 necesita llamar a la función “refreshDrawableState”, al menos la solución funciona bien tal como está, 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)

    • Usted puede como weel mezclar estados estándar (por ejemplo, android: presionado, android: habilitado, android: seleccionado) con estados personalizados, para representar combinaciones de estado más complicadas

    Este hilo muestra cómo agregar estados personalizados a botones y similares. (Si no puede ver los nuevos grupos de Google en su navegador, aquí hay una copia del hilo).

    No olvides llamar a refreshDrawableState dentro del hilo de UI:

     mHandler.post(new Runnable() { @Override public void run() { refreshDrawableState(); } }); 

    Me llevó mucho tiempo averiguar por qué mi botón no cambiaba su estado, aunque todo parecía correcto.