Cómo: Definir elemento de tema (estilo) para el widget personalizado
He escrito un widget personalizado para un control que usamos ampliamente en toda nuestra aplicación. La clase widget deriva de ImageButton
y lo extiende de un par de maneras simples. He definido un estilo que puedo aplicar al widget como se utiliza, pero prefiero configurar esto a través de un tema. En R.styleable
veo los atributos del estilo del widget como imageButtonStyle
y textViewStyle
. ¿Hay alguna manera de crear algo así para el widget personalizado que escribí?
- Android Material Design: No se pudo encontrar el estilo 'toolbarStyle' en el tema actual
- Android Action Bar es nulo cuando se utiliza Theme.Wallpaper
- Configuración del color de fondo del tema de Android
- Java.lang.IllegalArgumentException: Necesita utilizar un tema Theme.AppCompat (o descendente) con la biblioteca de diseño
- Cambiar el color del tema en Runtime en Android
- Buscar dinámicamente el nombre del tema en la aplicación de Android
- ¿Cómo puedo modificar Theme.Holo.Light.Dialog para ocupar menos espacio en la pantalla?
- Crear tema personalizado descargable y aplicarlo durante el tiempo de ejecución
- Tema predeterminado de Android
- Vista previa de tema falla en Eclipse
- ¿Qué hace el AppBaseTheme en las aplicaciones Android
- Temas de Android - definición de colores en temas personalizados
- ¿Cómo cambiar de tema (modo nocturno) sin reiniciar la actividad?
Sí, hay una manera:
Supongamos que tiene una declaración de atributos para su widget (en attrs.xml
):
<declare-styleable name="CustomImageButton"> <attr name="customAttr" format="string"/> </declare-styleable>
Declare un atributo que utilizará para una referencia de estilo (en attrs.xml
):
<declare-styleable name="CustomTheme"> <attr name="customImageButtonStyle" format="reference"/> </declare-styleable>
Declare un conjunto de valores de atributo por defecto para el widget (en styles.xml
):
<style name="Widget.ImageButton.Custom" parent="android:style/Widget.ImageButton"> <item name="customAttr">some value</item> </style>
Declare un tema personalizado (en themes.xml
):
<style name="Theme.Custom" parent="@android:style/Theme"> <item name="customImageButtonStyle">@style/Widget.ImageButton.Custom</item> </style>
Utilice este atributo como el tercer argumento en el constructor de su widget (en CustomImageButton.java
):
public class CustomImageButton extends ImageButton { private String customAttr; public CustomImageButton( Context context ) { this( context, null ); } public CustomImageButton( Context context, AttributeSet attrs ) { this( context, attrs, R.attr.customImageButtonStyle ); } public CustomImageButton( Context context, AttributeSet attrs, int defStyle ) { super( context, attrs, defStyle ); final TypedArray array = context.obtainStyledAttributes( attrs, R.styleable.CustomImageButton, defStyle, R.style.Widget_ImageButton_Custom ); // see below this.customAttr = array.getString( R.styleable.CustomImageButton_customAttr, "" ); array.recycle(); } }
Ahora tienes que aplicar Theme.Custom
a todas las actividades que utilizan CustomImageButton
(en AndroidManifest.xml):
<activity android:name=".MyActivity" android:theme="@style/Theme.Custom"/>
Eso es todo. Ahora CustomImageButton
intenta cargar los valores de atributo predeterminados del atributo customImageButtonStyle
del tema actual. Si no se encuentra tal atributo en el valor del tema o atributo es @null
entonces se @null
el argumento final para obtainStyledAttributes
: Widget.ImageButton.Custom
en este caso.
Puede cambiar los nombres de todas las instancias y todos los archivos (excepto AndroidManifest.xml
), pero sería mejor utilizar la convención de nomenclatura de Android.
Otro aspecto, además de la respuesta excelente de Michael es la sustitución de atributos personalizados en los temas. Suponga que tiene varias vistas personalizadas que se refieren al atributo personalizado "custom_background".
<declare-styleable name="MyCustomStylables"> <attr name="custom_background" format="color"/> </declare-styleable>
En un tema se define cuál es el valor
<style name="MyColorfulTheme" parent="AppTheme"> <item name="custom_background">#ff0000</item> </style>
o
<style name="MyBoringTheme" parent="AppTheme"> <item name="custom_background">#ffffff</item> </style>
Puede hacer referencia al atributo en un estilo
<style name="MyDefaultLabelStyle" parent="AppTheme"> <item name="android:background">?background_label</item> </style>
Observe el signo de interrogación, como también se utiliza para el atributo android de referencia como en
?android:attr/colorBackground
Como la mayoría de ustedes han notado, pueden -y probablemente deberían usar- referencias @color en vez de colores codificados.
Entonces, ¿por qué no simplemente hacer
<item name="android:background">@color/my_background_color</item>
No puedes cambiar la definición de "my_background_color" en tiempo de ejecución, mientras que puedes cambiar fácilmente los temas.