Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

setColorFilter is deprecated on API29

Tags:

android

I use the following line to change the color of a VectorDrawable:

mydrawable.getBackground().setColorFilter(color, PorterDuff.Mode.SRC_ATOP)

This works nice, though it is now deprecated. The documentation suggests that I use:

mydrawable.getBackground().setColorFilter(new BlendModeColorFilter(color, PorterDuff.Mode.SRC_ATOP))

Though, BlendModeColorFilter is only available on API29. After examining the source of the deprecated method, I have realized that it calls:

new PorterDuffColorFilter()

So, I went ahead and used:

mydrawable.getBackground().setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP))

The coloring worked. Is this the right replacement for the deprecated method or I must use BlendModeColorFilter on API29?

Thank you.

like image 477
Migrata Nomos Avatar asked Jun 22 '19 14:06

Migrata Nomos


3 Answers

Try this:

public class MyDrawableCompat {
    public static void setColorFilter(@NonNull Drawable drawable, @ColorInt int color) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            drawable.setColorFilter(new BlendModeColorFilter(color, BlendMode.SRC_ATOP));
        } else {
            drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
        }
    }
}

And this:

MyDrawableCompat.setColorFilter(mydrawable.getBackground(), color);

UPDATE: Just use the latest version of the core androidx library and this code:

mydrawable.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_ATOP)
like image 113
shmakova Avatar answered Nov 14 '22 23:11

shmakova


Use androidx.core:core:1.2.0 or androidx.core:core-ktx:1.2.0.

// Java
implementation 'androidx.core:core:1.2.0'
// Kotlin
implementation 'androidx.core:core-ktx:1.2.0'

And this:

drawable.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_ATOP))
like image 76
Wataru Mukainakano Avatar answered Nov 14 '22 22:11

Wataru Mukainakano


Thanks to @shmakova I added a solution for Kotlin.

import android.graphics.BlendMode
import android.graphics.BlendModeColorFilter
import android.graphics.PorterDuff
import android.graphics.drawable.Drawable
import android.os.Build
import androidx.annotation.RequiresApi

fun Drawable.setColorFilter(color: Int, mode: Mode = Mode.SRC_ATOP) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        colorFilter = BlendModeColorFilter(color, mode.getBlendMode())
    } else {
        @Suppress("DEPRECATION")
        setColorFilter(color, mode.getPorterDuffMode())
    }
}

// This class is needed to call the setColorFilter 
// with different BlendMode on older API (before 29).
enum class Mode {
    CLEAR,
    SRC,
    DST,
    SRC_OVER,
    DST_OVER,
    SRC_IN,
    DST_IN,
    SRC_OUT,
    DST_OUT,
    SRC_ATOP,
    DST_ATOP,
    XOR,
    DARKEN,
    LIGHTEN,
    MULTIPLY,
    SCREEN,
    ADD,
    OVERLAY;

    @RequiresApi(Build.VERSION_CODES.Q)
    fun getBlendMode(): BlendMode =
        when (this) {
            CLEAR -> BlendMode.CLEAR
            SRC -> BlendMode.SRC
            DST -> BlendMode.DST
            SRC_OVER -> BlendMode.SRC_OVER
            DST_OVER -> BlendMode.DST_OVER
            SRC_IN -> BlendMode.SRC_IN
            DST_IN -> BlendMode.DST_IN
            SRC_OUT -> BlendMode.SRC_OUT
            DST_OUT -> BlendMode.DST_OUT
            SRC_ATOP -> BlendMode.SRC_ATOP
            DST_ATOP -> BlendMode.DST_ATOP
            XOR -> BlendMode.XOR
            DARKEN -> BlendMode.DARKEN
            LIGHTEN -> BlendMode.LIGHTEN
            MULTIPLY -> BlendMode.MULTIPLY
            SCREEN -> BlendMode.SCREEN
            ADD -> BlendMode.PLUS
            OVERLAY -> BlendMode.OVERLAY
        }

    fun getPorterDuffMode(): PorterDuff.Mode =
        when (this) {
            CLEAR -> PorterDuff.Mode.CLEAR
            SRC -> PorterDuff.Mode.SRC
            DST -> PorterDuff.Mode.DST
            SRC_OVER -> PorterDuff.Mode.SRC_OVER
            DST_OVER -> PorterDuff.Mode.DST_OVER
            SRC_IN -> PorterDuff.Mode.SRC_IN
            DST_IN -> PorterDuff.Mode.DST_IN
            SRC_OUT -> PorterDuff.Mode.SRC_OUT
            DST_OUT -> PorterDuff.Mode.DST_OUT
            SRC_ATOP -> PorterDuff.Mode.SRC_ATOP
            DST_ATOP -> PorterDuff.Mode.DST_ATOP
            XOR -> PorterDuff.Mode.XOR
            DARKEN -> PorterDuff.Mode.DARKEN
            LIGHTEN -> PorterDuff.Mode.LIGHTEN
            MULTIPLY -> PorterDuff.Mode.MULTIPLY
            SCREEN -> PorterDuff.Mode.SCREEN
            ADD -> PorterDuff.Mode.ADD
            OVERLAY -> PorterDuff.Mode.OVERLAY
        }
}

Use it as usually:

toolbar?.navigationIcon?.setColorFilter(ContextCompat.getColor(this, color)) /* 1 */
progressBar.indeterminateDrawable.setColorFilter(color, Mode.SRC_IN) /* 2 */

I tried to call setColorFilter with both BlendMode and PorterDuff.Mode parameters (like drawable.setColorFilter(color, BlendMode.SRC_ATOP, PorterDuff.Mode.SRC_ATOP)), but that led to a runtime exception:

java.lang.NoClassDefFoundError: Failed resolution of: Landroid/graphics/BlendMode;

So, we can call any method with BlendMode only starting from SDK version 29 (it was added there). I had to create setColorFilter with Mode parameter.

like image 13
CoolMind Avatar answered Nov 15 '22 00:11

CoolMind