简体   繁体   English

API29 上不推荐使用 setColorFilter

[英]setColorFilter is deprecated on API29

I use the following line to change the color of a VectorDrawable:我使用以下行来更改 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.但是, BlendModeColorFilter仅在 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?这是已弃用方法的正确替代品,还是我必须在 API29 上使用 BlendModeColorFilter?

Thank you.谢谢你。

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:更新:只需使用最新版本的核心 androidx 库和此代码:

mydrawable.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, BlendModeCompat.SRC_ATOP)

Use androidx.core:core:1.2.0 or androidx.core:core-ktx:1.2.0 .使用androidx.core:core:1.2.0androidx.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))

Thanks to @shmakova I added a solution for Kotlin.感谢 @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
        }
}

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:我尝试使用BlendModePorterDuff.Mode参数(如drawable.setColorFilter(color, BlendMode.SRC_ATOP, PorterDuff.Mode.SRC_ATOP) )调用setColorFilter ,但这导致运行时异常:

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

So, we can call any method with BlendMode only starting from SDK version 29 (it was added there).因此,我们只能从 SDK 版本 29(它被添加到那里)开始使用BlendMode调用任何方法。 I had to create setColorFilter with Mode parameter.我必须使用Mode参数创建setColorFilter

PorterDuffColorFilter was added in API level 1 and it's not deprecated, in addition PorterDuffColorFilter is a subclass of ColorFilter . PorterDuffColorFilter是在 API 级别 1 中添加的,并没有被弃用,此外PorterDuffColorFilterColorFilter的子类。 You may use it as you did with no problems as setColorFilter parameter is of type ColorFilter and it does not require you to pass a BlendModeColorFilter .您可以像以前一样使用它,因为setColorFilter参数属于ColorFilter类型,并且不需要您传递BlendModeColorFilter The are many reasons why the documentation may suggests BlendModeColorFilter .文档可能建议BlendModeColorFilter原因有很多。 Maybe they plan on deprecating PorterDuffColorFilter in the future (as of 2021 it is still not deprecated) or maybe it just performs better, who knows... The point is that you used it correctly.也许他们计划在未来弃用PorterDuffColorFilter (截至 2021 年,它还没有被弃用),或者它的性能更好,谁知道呢……关键是你正确地使用了它。 If you want to safeguard against your code breaking down because PorterDuffColorFilter suddenly got deprecated and removed then you should do what many others have suggested and add a Version check.如果您想防止您的代码因为PorterDuffColorFilter突然被弃用和删除而PorterDuffColorFilter ,那么您应该按照许多其他人的建议进行操作并添加版本检查。 If you are not worried about that then you don't have to do it but you will have to keep an eye out for any future changes.如果您不担心,那么您不必这样做,但您必须留意未来的任何变化。

But all in all as of 2021 your code will work on all versions.但总而言之,到 2021 年,您的代码将适用于所有版本。

Regards问候

NOTE: setColorFilter(int color, PorterDuff.Mode mode) is deprecated this answer is only relevant to setColorFilter(ColorFilter colorFilter)注意: setColorFilter(int color, PorterDuff.Mode mode)已弃用此答案仅与setColorFilter(ColorFilter colorFilter)

BlendMode Filters may require higher API to be working. BlendMode 过滤器可能需要更高的 API 才能工作。

check out this link to know more查看此链接以了解更多信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM