Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to: Define theme (style) item for custom widget

I've written a custom widget for a control that we use widely throughout our application. The widget class derives from ImageButton and extends it in a couple of simple ways. I've defined a style which I can apply to the widget as it's used, but I'd prefer to set this up through a theme. In R.styleable I see widget style attributes like imageButtonStyle and textViewStyle. Is there any way to create something like that for the custom widget I wrote?

like image 913
jsmith Avatar asked Dec 20 '10 21:12

jsmith


People also ask

How do you style widgets on android?

This example demonstrates how do I Style an Android Switch Widget in android. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main. xml.

Which tag is used to define themes?

You can create a theme the same way you create styles. The difference is how you apply it: instead of applying a style with the style attribute on a view, you apply a theme with the android:theme attribute on either the <application> tag or an <activity> tag in the AndroidManifest.

What is theme AppCompat?

The AppCompat support library provides themes to build apps with the Material Design specification. A theme with a parent of Theme. AppCompat is also required for an Activity to extend AppCompatActivity . The first step is to customize your theme's color palette to automatically colorize your app.


2 Answers

Yes, there's one way:

Suppose you have a declaration of attributes for your widget (in attrs.xml):

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

Declare an attribute you will use for a style reference (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 your widget's 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 have to apply Theme.Custom to all activities that use CustomImageButton (in AndroidManifest.xml):

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

That's all. Now CustomImageButton tries to load default attribute values from customImageButtonStyle attribute of current theme. If no such attribute is found in the theme or attribute's value is @null then the final argument to obtainStyledAttributes will be used: Widget.ImageButton.Custom in this case.

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

like image 138
Michael Avatar answered Sep 22 '22 06:09

Michael


Another aspect in addition to michael's excellent answer is overriding custom attributes in themes. Suppose you have a number of custom views that all refer to the custom attribute "custom_background".

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

In a theme you define what the value is

<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 the attribute in a style

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

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

?android:attr/colorBackground 

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

So why not just do

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

You can not change the definition of "my_background_color" at runtime, whereas you can easily switch themes.

like image 42
mir Avatar answered Sep 22 '22 06:09

mir