How to fix Drawable.setTint bug in API 21 Android SDK

Hi, in this post, our android developer Vlad Titov will talk about how to solve the problem using the color change tool for Drawable. Go.

In the 21st version of the Android SDK API, there is a universal tool for changing the color for all Drawable - Drawable.setTint (int color) . But just in this very version, it does not work for some inheritors of Drawable, namely GradientDrawable, InsetDrawable, RippleDrawable and all descendants of DrawableContainer. 

If we look at the API 21 sources, say, GradientDrawable (direct descendant of Drawable), we will not find the overridden setTint method and its variations. This means that in this implementation, the developers simply did not support this function.

. androidx.core:core. tinting 14-22, WrappedDrawableApi14 WrappedDrawableApi21. , , . 

Drawable, DrawableCompat.wrap(Drawable). , ColorStateList , Drawable Drawable.

final ColorStateList tintList = mState.mTint;
final PorterDuff.Mode tintMode = mState.mTintMode;

if (tintList != null && tintMode != null) {
   final int color = tintList.getColorForState(state, tintList.getDefaultColor());
   if (!mColorFilterSet || color != mCurrentColor || tintMode != mCurrentMode) {
       setColorFilter(color, tintMode);
       mCurrentColor = color;
       mCurrentMode = tintMode;
       mColorFilterSet = true;
       return true;
   }
} else {
   mColorFilterSet = false;
   clearColorFilter();
}

Drawable.setState(int[] stateSet).

Drawable. , , GradientDrawable , , setShape, setGradientType ... , Drawable (DrawableCompat.unwrap(Drawable)). . , , Drawable. stateful, , , .

, . 

If your tint consists of only one color, you can do the following at any time:

val wrapped = DrawableCompat.wrap(drawable)
wrapped.setTint(...)
drawable = DrawableCompat.unwrap(wrapped)

After that, boldly do your business further.

Otherwise, it makes sense to use the following solution:

class GradientDrawableWrapper(
    val original: GradientDrawable, 
    var tint: ColorStateList
) {

    fun get(): Drawable {
        return wrap()
    }

    fun setShape(@Shape shape: Int) {
        original.setShape(shape)
    }

    // other specific method proxies...

    private fun wrap(): Drawable {
        val wrapped = DrawableCompat.wrap(original)
        wrapped.setTint(tint)
        return wrapped
    }
}

This solution looks a bit voluminous, but it completely solves the indicated problem.




All Articles