Skip to content

Custom attributes

ZieIony edited this page Oct 27, 2019 · 2 revisions

First thing to do to add a custom attribute is to declare a styleable in XML. A styleable is an XML with a bunch of attributes that will be used by a custom view.

You will also need an attribute for the styleable to use. You can either add your own attribute (remember to prefix it) or reuse an existing one. Your attributes can be declared and then used in a styleable or declared and used at once. Reusing attributes is just as easy - just remember to use the same namespace, name and type as the original declaration.

<resources>
    // declaration
    <attr name="carbon_rippleColor" format="color"/>

    <declare-styleable name="ImageView">
        // usage
        <attr name="carbon_rippleColor"/>
        
        // declaration and usage in one line
        <attr name="carbon_rippleHotspot" format="boolean"/>
        
        // reuse of android attr, skip the type
        <attr name="android:menu"/>
    </declare-styleable>
</resources>

For a custom view, you may want to add a theme attribute. That attribute will be used by the view to read the default style provided by a theme. It's just a simple reference attribute, usually with a style suffix.

<resources>
    // style reference for use in themes
    <attr name="carbon_imageViewStyle" format="reference"/>
</resources>

You also need a style. It can be a base style (if it's a completely new style) or a derived style (if there was a parent style you could use).

<resources>
    <style name="carbon_ImageView">
        <item name="carbon_rippleColor">@null</item>
        <item name="carbon_rippleHotspot">false</item>
        <item name="android:menu">@menu/main</item>
    </style>
    
    // extend the default style of the view's parent class if there is one
    <style name="carbon_Button" parent="@android:style/Widget.Button"/>
</resources>

Then declare a theme in themes.xml and use the style attribute to set the style.

<resources>
    <style name="carbon_Theme.Light" parent="Theme.MaterialComponents.Light">
        <item name="carbon_imageViewStyle">@style/carbon_ImageView</item>
    </style>
</resources>

The attributes are passed to a view in a couple of ways:

  • Using base theme values.

  • Using a default style resource. This way corresponds to the 4th parameter in the 4-parameter constructor and the 4th parameter in obtainStyledAttributes(). It's a reference to the default style for a view. If this value is 0, it won't be used to look for defaults.

  • Style using the theme attribute. This way corresponds to the 3rd parameter in the 3 and 4-parameter constructors and the 3rd parameter in obtainStyledAttributes(). It's a reference to a style specified in the current theme. If this value is 0, it won't be used to look for defaults.

  • Style using the style attribute and using inline attribute usage in a layout. These come in AttributeSet attrs. Can be null if the view was created without using an XML layout.

  • Default values applied when grabbing attribute values from value arrays.

public class ImageView extends android.widget.ImageView {

    public ImageView(Context context) {
        super(context, null, R.attr.carbon_imageViewStyle);
        initImageView(null, R.attr.carbon_imageViewStyle);
    }

    public ImageView(Context context, AttributeSet attrs) {
        super(context, attrs, R.attr.carbon_imageViewStyle);
        initImageView(attrs, R.attr.carbon_imageViewStyle);
    }

    private void initImageView(AttributeSet attrs, int defStyleAttr) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ImageView, defStyleAttr, R.style.carbon_ImageView);

        setRippleColor(a.getColorStateList(R.styleable.ImageView_carbon_rippleColor));
        setRippleHotspot(a.Boolean(R.styleable.ImageView_carbon_rippleHotspot, false));
        setMenu(a.getResourceId(R.styleable.ImageView_android_menu, 0);

        a.recycle();
    }
}

In a typical case, you need only two constructors and a bit of initialization code. obtainStyledAttributes() is used to get an array of values for this view considering default style, the current theme and XML attributes. Then, attribute by attribute, you have to get a value by id and set it to the view. Notice how the attribute names declared in XML (with namespaces) are transformed to field names of the ids in the example.

Clone this wiki locally