setColorFilter在API29上已弃用

Mig*_*mos 15 android

我使用以下行更改VectorDrawable的颜色:

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

尽管现在已不推荐使用,但效果很好。该文档建议我使用:

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

虽然,BlendModeColorFilter仅在API29上可用。在检查了不赞成使用的方法的源之后,我意识到它调用了:

new PorterDuffColorFilter()

因此,我继续使用:

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

着色工作。这是不推荐使用的方法的正确替代方法,还是我必须在API29上使用BlendModeColorFilter?

谢谢。

shm*_*ova 24

尝试这个:

public class MyDrawableCompat {
    public static void setColorFilter(@NonNull Drawable drawable, 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

和这个:

MyDrawableCompat.setColorFilter(mydrawable.getBackground(), color);
Run Code Online (Sandbox Code Playgroud)

  • 或者用一行代码`drawable.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_ATOP)` (3认同)
  • 感谢您花时间编写方法,shmakova。我很感激。如果我无法验证 `new PorterDuffColorFilter()` 是否正常工作,这就是我必须要做的。在使用它时,我必须手动替换每个条目,而且我有 100 多个条目。我希望有人能对“new PorterDuffColorFilter()”有所了解 (2认同)

Coo*_*ind 11

感谢 @shmakova,我为 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
        }
}
Run Code Online (Sandbox Code Playgroud)

像往常一样使用它:

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

我尝试setColorFilter同时使用BlendModePorterDuff.Mode参数(如drawable.setColorFilter(color, BlendMode.SRC_ATOP, PorterDuff.Mode.SRC_ATOP))进行调用,但这导致了运行时异常:

java.lang.NoClassDefFoundError:解析失败:Landroid/graphics/BlendMode;

因此,我们只能从 SDK 版本 29(它被添加到那里)开始使用BlendMode调用任何方法。我必须setColorFilterMode参数创建。


小智 9

使用androidx.core:core:1.2.0-beta01androidx.core:core-ktx:1.2.0-beta01

// Java
implementation 'androidx.core:core:1.2.0-beta01'
// Kotlin
implementation 'androidx.core:core-ktx:1.2.0-beta01'
Run Code Online (Sandbox Code Playgroud)

和这个:

drawable.setColorFilter(BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_ATOP))
Run Code Online (Sandbox Code Playgroud)

  • 使用此替代方案时请小心。我首先尝试了这个,但使用“Multiply”混合模式时,结果与“mydrawable.getBackground().setColorFilter(color, PorterDuff.Mode.MULTIPLY)”不匹配。这个解决方案似乎效果最好,并保持相同的预期视觉结果:`mydrawable.getBackground().setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY))` (5认同)
  • 谷歌是否与某人签订了合同来打扰我们?:| 为什么它让一切变得复杂? (5认同)
  • 这个应该是Beta接受的答案 (2认同)
  • 还要补充一件事。我查看了 BlendModeUtils 的源代码(位于此处:https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/core/core/src/main/ java/androidx/core/graphics/BlendModeUtils.java?source=post_page----------------------------------------%2F%2F%2F%2F %2F%2F%2F&autodive=0%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F 看来 `MULTIPLY` 映射到 API29 的 `MULTIPLY` (仅)使用 ` BlendMode` 否则,对于所有其他 API,`MODULATE` 使用 `PorterDuff.Mode` 映射到 `MULTIPLY`。 (2认同)