Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setColorFilter doesn't seem to work on kitkat

I'm attempting to colorize a graphic using setColorFilter. The following code seems to work fine on lollipop, but it seems to have no effect on kitkat, the icon is rendered in it's original colors:

Drawable icon = ContextCompat.getDrawable(context, R.drawable.ic_chat_button).mutate();
icon.setColorFilter(context.getResources().getColor(R.color.control_tint_color), PorterDuff.Mode.SRC_ATOP);
icon.invalidateSelf();

The mutate and invalidateSelf calls don't seem to have any effect on the problem here, just leaving them in as an example of part of what's been tried to figure out what's going on.

FWIW, I'm using the drawable as part of a LayerDrawable in a StateListDrawable that gets used as either the background for a button or as the drawable for an ImageView The results are consistent (ie., wrong on kitkat) either way. I've also tried putting the icon drawable directly into the StateListDrawable again with no change in behavior. In all cases, it works fine on lollipop, but doesn't work on kitkat.

As an experiment, I took the tinted Drawable out of the StateListDrawable but not the LayerDrawable and it works as expected. Apparently there's something flawed in KitKat's implementation of StateListDrawable that prevents it from working, that has been remedied in later versions.

like image 995
David Berry Avatar asked Feb 10 '23 11:02

David Berry


1 Answers

Ultimately, it seems like the problem is that KitKat doesn't support using a ColorFilter (or implicitly an alpha) on a Drawable that will in turn be in a StateListDrawable. My solution was to use the same to code to construct the complex Drawable and then render that into a simple BitMapDrawable:

static Drawable createDrawable(Context context, int color, boolean disabled) {
    OvalShape oShape = new OvalShape();
    ShapeDrawable background = new ShapeDrawable(oShape);
    background.getPaint().setColor(color);

    ShapeDrawable shader = new ShapeDrawable(oShape);
    shader.setShaderFactory(new ShapeDrawable.ShaderFactory() {
        @Override
        public Shader resize(int width, int height) {
            return new LinearGradient(0, 0, 0, height,
                    new int[]{
                            Color.WHITE,
                            Color.GRAY,
                            Color.DKGRAY,
                            Color.BLACK
                    }, null, Shader.TileMode.REPEAT);
        }
    });

    Drawable icon = ContextCompat.getDrawable(context, R.drawable.ic_chat_button).mutate();
    icon.setColorFilter(context.getResources().getColor(R.color.control_tint_color), PorterDuff.Mode.SRC_IN);

    Drawable layer = new LayerDrawable(new Drawable[]{ shader, background, icon });
    layer.setAlpha(disabled ? 128 : 255);

    // Note that on KitKat, setting a ColorFilter on a Drawable contained in a StateListDrawable
    //  apparently doesn't work, although it does on later versions, so we have to render the colored
    //  bitmap into a BitmapDrawable and then put that into the StateListDrawable
    Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);

    layer.setBounds(0, 0, layer.getIntrinsicWidth(), layer.getIntrinsicHeight());
    layer.draw(canvas);

    return new BitmapDrawable(context.getResources(), bitmap);
}
like image 76
David Berry Avatar answered Feb 15 '23 17:02

David Berry