Android: Tint using DrawableCompat

AndroidCompatibilityTint

Android Problem Overview


I'm trying to tint an image prior to Android API level 21. I've successfully tinted items using:

<android:tint="@color/red"/>

However, I can't seem to figure out how to do this through code on an ImageView:

Drawable iconDrawable = this.mContext.getResources().getDrawable(R.drawable.somedrawable);
DrawableCompat.setTint(iconDrawable, this.mContext.getResources().getColor(R.color.red));
imageView.setImageDrawable(iconDrawable);

I've tried setting the TintMode but this seems to make no different. Am I using the v4 compatibility class DrawableCompat incorrectly?

Android Solutions


Solution 1 - Android

In case anyone needs to use DrawableCompat's tinting without affecting other drawables, here's how you do it with mutate():

Drawable drawable = getResources().getDrawable(R.drawable.some_drawable);
Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
wrappedDrawable = wrappedDrawable.mutate();
DrawableCompat.setTint(wrappedDrawable, getResources().getColor(R.color.white));

Which can be simplified to:

Drawable drawable = getResources().getDrawable(R.drawable.some_drawable);
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable.mutate(), getResources().getColor(R.color.white));

Solution 2 - Android

Previously tinting was not supported by DrawableCompat. Starting from support library 22.1 you can do that, but you need do it in this way:

Drawable normalDrawable = getResources().getDrawable(R.drawable.drawable_to_tint);
Drawable wrapDrawable = DrawableCompat.wrap(normalDrawable);
DrawableCompat.setTint(wrapDrawable, getResources().getColor(R.color.colorPrimaryLight));

Solution 3 - Android

The simplest way to tint cross-platform (if you don't need a ColorStateList) is:

drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);

Don't forget to mutate the Drawable before applying the filter.

Solution 4 - Android

The answers here are not working for pre-lollipop-devices (SupportLib 23.4.0) but I've posted a workaround which is working for API 17 and up: https://stackoverflow.com/a/37434219/2170109

The following code was tested and is working on APIs 17, 19, 21, 22, 23 and N Preview 3:

    // https://stackoverflow.com/a/30928051/2170109
    Drawable drawable = DrawableCompat.wrap(ContextCompat.getDrawable(context, R.drawable.vector));
    image.setImageDrawable(drawable);

    /*
     * need to use the filter | https://stackoverflow.com/a/30880522/2170109
     * (even if compat should use it for pre-API21-devices | https://stackoverflow.com/a/27812472/2170109)
     */
    int color = ContextCompat.getColor(context, R.color.yourcolor);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        DrawableCompat.setTint(drawable, color);

    } else {
        drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
    }

Solution 5 - Android

If you look at the source code for DrawableCompat you will see that for any version < 21 the method does nothing.

The idea of DrawableCompat seems to be simply not crashing on old versions, rather than actually providing that functionality.

Solution 6 - Android

With support library 22.1 you can use DrawableCompat to tint drawables.

> DrawableCompat.wrap(Drawable) and setTint(), setTintList(), and setTintMode() will just work: no need to create and maintain separate drawables only to support multiple colors!

Solution 7 - Android

I'll share my solution here because it may save some time to somebody.

I had an ImageView with vector drawable used as its source drawable (actually, it was Support Vector Drawable from Android Support Library 23.3). So, first I've wrapped it like so:

mImageView.setImageDrawable(DrawableCompat.wrap(mImageView.getDrawable()));

And after that I tried to apply tint to it like so:

DrawableCompat.setTint(
    mImageView.getDrawable(),
    getResources().getColor(R.color.main_color)
);

No luck.

I tried to call mutate() on wrapped drawable, as well as on original drawable - still no luck. invalidate() called on mImageView did the trick.

Solution 8 - Android

to set a tint and a drawable to a view and make it backward compatible while supporting the current theme of context using kotlin and not checking for the current SDK version and avoid deprecated methods:

imageView.setImageDrawable(
            ContextCompat.getDrawable(context, R.drawable.somedrawable).apply {
                setTint(ContextCompat.getColor(context, R.color.red))
            })

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionHippopatimusView Question on Stackoverflow
Solution 1 - AndroidRenan FerrariView Answer on Stackoverflow
Solution 2 - AndroidSimon K. GergesView Answer on Stackoverflow
Solution 3 - AndroidBladeCoderView Answer on Stackoverflow
Solution 4 - AndroidhardysimView Answer on Stackoverflow
Solution 5 - AndroidMichael SmithView Answer on Stackoverflow
Solution 6 - AndroidbugraoralView Answer on Stackoverflow
Solution 7 - AndroidagaView Answer on Stackoverflow
Solution 8 - AndroidAmin KeshavarzianView Answer on Stackoverflow