Custom Themes for Custom Widgets

  • Tutorial
While developing HoloEverywhere, I was faced with the fact that most of the questions sent to me in one way or another relate to how to style any widgets.

That is, people do not particularly understand the very principle of the work of themes and attributes.
Let's try to chew this topic a little.

For starters: what are styles in general? A set of values ​​for attributes.
And where is the list of these attributes, how to get their values?
Styleable resources.

Let's do it the old fashioned way: create your view:
package habra.tutorial.customwidget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
public class HabraWidget extends View {
    public HabraWidget(Context context) {
        super(context);
    }
    public HabraWidget(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public HabraWidget(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
}


Have you ever wondered what this last, third, argument is in the constructor? int defStyle?

You will have time to think, but for now we will create our first attribute, the value of which will lie in the topic for Activity or even for the entire application ...
Create values ​​/ attrs.xml (the name is not fundamental, at least in strings.xml)

In Android, the names of attributes for styles for widgets are usually set by the name of the widget in camelCase + postfix Style.
And format sets, oddly enough, the format of the values. Leave here reference, i.e. link to the resource, in this case, to the style.

Now we modify the constructors of our widget. Now they just call the parent constructor.
And now the defStyle feature - it sets the name of the attribute, by default values ​​from the style that this attribute refers to will be used.
    public HabraWidget(Context context) {
        this(context, null);
    }
    public HabraWidget(Context context, AttributeSet attrs) {
        this(context, attrs, R.attr.habraWidgetStyle);
    }

Those. the HabraWidget (Context) constructor will call HabraWidget (Context, AttributeSet) with the second argument null,
and it in turn will call HabraWidget (Context, AttributeSet, int) with our attribute.

Now we’ll decide, and what, in fact, will our widget do? Let him draw a simple cross from his corners:
    private final Paint paint;
    public HabraWidget(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        paint = new Paint();
        paint.setColor(0xFF00EEFF);
        paint.setStyle(Style.FILL_AND_STROKE);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawLine(0, 0, getWidth(), getHeight(), paint);
        canvas.drawLine(getWidth(), 0, 0, getHeight(), paint);
    }

Great, but the color of the line is hard coded in the code (0xFF00EEFF), you think about the same thing, what am I talking about? Take out in styles!
First, create a styleable with an attribute ... well, say, lineColor:
attrs.xml


And create a default style:
styles.xml


And how to pull out the color now?
TypedArray:
    public HabraWidget(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.HabraWidget, defStyle,
                R.style.HabraWidget);
        paint = new Paint();
        paint.setColor(a.getColor(R.styleable.HabraWidget_lineColor, 0xFFFF0000));
        paint.setStyle(Style.FILL_AND_STROKE);
        a.recycle();
    }

0xFFFF0000 - default color. It is possible to transmit some zero, since we have indicated the default topic.
Well, do not forget to do a recycle after you have pulled out all the data.
Further feature concerning the creation of layout. We are used to the fact that all attributes are set via the android :.
But since our attributes are not in the android package, then the namespace will be different.
I will give an example:

image

Now we are free to set the color of the lines from the markup.

Also popular now: