SetColorFilter doesn't seem to work on kitkat

I am trying to colorize graphics using setColorFilter

. The following code seems to work fine for lollipop, but it doesn't seem to affect kitkat, the icon is displayed in its 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();

      

Calling mutate

and invalidateSelf

doesn't seem to affect the problem here, just leaving them as an example of a part of what was trying to figure out what was going on.

FWIW, I am using a drawable as part LayerDrawable

in StateListDrawable

which is used as the background for a button or as a highlight for ImageView

. The results are consistent (i.e. wrong on kitkat) anyway. I also tried putting the icon in again StateListDrawable

without changing the behavior. In all cases, it works fine on lollipop, but doesn't work on kitkat.

As an experiment, I took the toned Drawable

from StateListDrawable

but not LayerDrawable

, and it works as expected. Apparently there is some bug in KitKat implementation StateListDrawable

that prevents it from working, which was fixed in later versions.

+3


source to share


2 answers


Ultimately it seems like the problem is that KitKat doesn't support using ColorFilter

(or implicitly alpha) on Drawable

, which in turn will be on StateListDrawable

. My solution was to use the same code to build a complex Drawable

one and then render it into a simple one 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);
}

      

+4


source


Rather than attaching the coloring to something like a "disabled" state (as in the accepted answer), I found the answer to be simpler, focusing on replay and letting my use be how to enable the rendered image in StateListDrawable

. (And FYI, I tried to translate from Xamarin C # which I am using, but the code below may not match correctly as Java)

static Drawable recolorDrawable(Drawable icon, int toColor)
{
    Bitmap bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
    Canvas myCanvas = new Canvas(bitmap);

    icon.setColorFilter(toColor, PorterDuff.Mode.SRC_IN);
    icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
    icon.draw(myCanvas);

    return new BitmapDrawable(context.getResources(), bitmap);
}

      



Finally, in all fairness to the accepted answer, I am quite foreign to Android development and can thank him for showing the parts I need and then simplifying them.

+4


source







All Articles