Mopper Mopper - 1 month ago 26
Java Question

StateListDrawable to switch colorfilters

I want to create custom buttons to use in a TabHost. I haven been trying to just use the same image resource (png), but have the colorfilter change depending on the state. So I made this bit to serve as the layout for the custom button:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android=""
android:layout_width="fill_parent" android:layout_height="fill_parent">
<ImageView android:id="@+id/tab_icon"
android:layout_centerInParent="true" android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" android:layout_width="wrap_content"
<TextView android:id="@+id/tab_text" android:layout_below="@id/tab_icon"
android:layout_centerHorizontal="true" android:layout_width="wrap_content"
android:layout_height="wrap_content" />

In my activity, I add the tabs like this:


And this is the 'buildTab' method:

private final static int[] SELECTED = new int[] { android.R.attr.state_selected };
private final static int[] IDLE = new int[] { -android.R.attr.state_selected };

private View buildTab(int icon, int label) {
LayoutInflater inflater = LayoutInflater.from(this);
View view = inflater.inflate(R.layout.tab_button, null);
StateListDrawable drawable = new StateListDrawable();

Drawable selected = getResources().getDrawable(icon);
selected.setBounds(0, 0, selected.getIntrinsicWidth(), selected.getIntrinsicHeight());
selected.setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0x0000FF00));
drawable.addState(SELECTED, selected);

Drawable idle = getResources().getDrawable(icon);
idle.setColorFilter(new LightingColorFilter(0xFFFFFFFF, 0x000000FF));
drawable.addState(IDLE, idle);

((ImageView) view.findViewById(;
((TextView) view.findViewById(;
return view;

In the selected state, the image should be completely green (
), and in the non-selected state, it should be blue (

The problem is that the colorfilters appear to be be completely ignored. I can not see the colors change under any circumstances.

I've also tried to get the same result by setting the
property on the
, but apparently you cannot use a reference to a
there, since it throws a

I don't see what I'm doing wrong so any help would be appreciated.


OK, I never got the above code to work, so here's what I ended up doing.

First, I subclassed LayerDrawable:

public class StateDrawable extends LayerDrawable {

    public StateDrawable(Drawable[] layers) {

    protected boolean onStateChange(int[] states) {
        for (int state : states) {
            if (state == android.R.attr.state_selected) {
                super.setColorFilter(Color.argb(255, 255, 195, 0), PorterDuff.Mode.SRC_ATOP);
            } else {
                super.setColorFilter(Color.GRAY, PorterDuff.Mode.SRC_ATOP);
        return super.onStateChange(states);

    public boolean isStateful() {
        return true;


I changed the buildTab() method to the following:

private View buildTab(int icon, int label) {
    LayoutInflater inflater = LayoutInflater.from(this);
    View view = inflater.inflate(R.layout.tab_button, null);
    ((ImageView) view.findViewById( StateDrawable(new Drawable[] { getResources()
          .getDrawable(icon) }));
    ((TextView) view.findViewById(;
    return view;

I still add the tabs like this:

Intent fooIntent = new Intent().setClass(this, FooActivity.class);

This works for me, compatible with android 1.6.