Por ejemplo, el botón predeterminado tiene las siguientes dependencias entre sus estados e imágenes de fondo:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true"
android:drawable="@drawable/btn_default_normal" />
<item android:state_window_focused="false" android:state_enabled="false"
android:drawable="@drawable/btn_default_normal_disable" />
<item android:state_pressed="true"
android:drawable="@drawable/btn_default_pressed" />
<item android:state_focused="true" android:state_enabled="true"
android:drawable="@drawable/btn_default_selected" />
<item android:state_enabled="true"
android:drawable="@drawable/btn_default_normal" />
<item android:state_focused="true"
android:drawable="@drawable/btn_default_normal_disable_focused" />
<item
android:drawable="@drawable/btn_default_normal_disable" />
</selector>
¿Cómo puedo definir mi propio estado personalizado (como algo android:state_custom
), para poder usarlo para cambiar dinámicamente la apariencia visual de mi botón?
Respuestas:
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":
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:
En la parte superior de la clase derivada:
Además, sus variables de estado:
Y un par de setters:
Luego anule la función "onCreateDrawableState":
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":
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
fuente
refreshDrawableState
definitivamente es importante. No estoy absolutamente seguro de cuándo es realmente necesario. Pero en mi caso era necesario al establecer el estado mediante programación. Supongo que posiblemente se llama desde la clase View automáticamente en onTouchEvent. Será mejor que lo agregue en el método setSelected.boolean
? ¿O los selectores solo funcionan en booleanos?Este hilo muestra cómo agregar estados personalizados a botones y similares. (Si no puede ver los nuevos grupos de Google en el navegador, no hay una copia de la rosca aquí .)
fuente
No olvides llamar
refreshDrawableState
dentro del hilo de la interfaz de usuario:Me tomó mucho tiempo descubrir por qué mi botón no cambia su estado a pesar de que todo parece correcto.
fuente