Question

It seems that StateListDrawable will ignore color filters applied to the drawables they contain. For example:

StateListDrawable sld = new StateListDrawable();
Drawable pressedState = Context.getResources().getDrawable(R.drawable.solid_green);

pressedState.setColorFilter(Color.RED, PorterDuff.Mode.SRC);

sld.addState(new int[] {android.R.attr.state_pressed}, pressedState);
// Other states...

If you apply sld to a view's background, you would expect the view's background to turn solid red when it is pressed. Instead, it would turn green - the color of pressedState with no filters applied.

Was it helpful?

Solution

To work around this, you have to apply the color filter to the StateListDrawable itself, based on the state the drawable is in. The following extension of StateListDrawable accomplishes this.

public class SelectorDrawable extends StateListDrawable {

    public SelectorDrawable(Context c) {
        super();

        addState(new int[] {android.R.attr.state_pressed}, c.getResources().getDrawable(R.drawable.solid_green));
        // Other states...
    }

    @Override
    protected boolean onStateChange(int[] states) {
        boolean isClicked = false;
        for (int state : states) {
            if (state == android.R.attr.state_pressed) {
                isClicked = true;
            }
        }

        if (isClicked)
            setColorFilter(Color.RED, PorterDuff.Mode.SRC);
        else
            clearColorFilter();

        return super.onStateChange(states);
    }
}

The logic in onStateChange(int[] states) can be extended further to test for more than just the pressed state, and different color filters can be applied accordingly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top