How to define a theme (style) for a custom widget

I wrote my own widget for a control that we widely use in our application. The widget class derives from ImageButton and extends it in several ways. I have defined a style that I can apply to the widget as it was used, but I would prefer to set this via the theme. In R.styleable I see widget style attributes such as imageButtonStyle and textViewStyle . Is there a way to create something like this for a custom widget that I wrote?

+68
android android-theme
Dec 20 '10 at 21:05
source share
2 answers

Yes, there is one way:

Suppose you have an attribute declaration for your widget (in attrs.xml ):

 <declare-styleable name="CustomImageButton"> <attr name="customAttr" format="string"/> </declare-styleable> 

Declare the attribute that you will use to reference the style (in attrs.xml ):

 <declare-styleable name="CustomTheme"> <attr name="customImageButtonStyle" format="reference"/> </declare-styleable> 

Declare a set of default attribute values ​​for the widget (in styles.xml ):

 <style name="Widget.ImageButton.Custom" parent="android:style/Widget.ImageButton"> <item name="customAttr">some value</item> </style> 

Declare a custom theme (in themes.xml ):

 <style name="Theme.Custom" parent="@android:style/Theme"> <item name="customImageButtonStyle">@style/Widget.ImageButton.Custom</item> </style> 

Use this attribute as the third argument in the widget constructor (in 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(); } } 

Now you need to apply Theme.Custom to all actions using CustomImageButton (in AndroidManifest.xml):

 <activity android:name=".MyActivity" android:theme="@style/Theme.Custom"/> 

It's all. CustomImageButton now CustomImageButton to load the default attribute values ​​from the customImageButtonStyle attribute of the current theme. If such an attribute is not found in the tag or value of the @null attribute, then the last obtainStyledAttributes argument will be used: Widget.ImageButton.Custom .

You can change the names of all instances and all files (except AndroidManifest.xml ), but it would be better to use the Android naming convention.

+177
Feb 19 '11 at 17:39
source share

Another aspect in addition to Michael's excellent answer is overriding custom attributes to themes. Suppose you have several custom views, which all refer to the custom_background attribute.

 <declare-styleable name="MyCustomStylables"> <attr name="custom_background" format="color"/> </declare-styleable> 

In a topic, you determine what value

 <style name="MyColorfulTheme" parent="AppTheme"> <item name="custom_background">#ff0000</item> </style> 

or

 <style name="MyBoringTheme" parent="AppTheme"> <item name="custom_background">#ffffff</item> </style> 

You can refer to an attribute in the style of

 <style name="MyDefaultLabelStyle" parent="AppTheme"> <item name="android:background">?background_label</item> </style> 

Note the question mark, also used for the android reference attribute, as in

 ?android:attr/colorBackground 

As most of you have noticed, you can - and probably should use @color links instead of hard-coded colors.

So why not just do

 <item name="android:background">@color/my_background_color</item> 

You cannot change the definition of "my_background_color" at run time, while you can easily switch themes.

0
Jul 13 '17 at 7:54 on
source share



All Articles