感谢 @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
}
}
按照通常的方式使用:
toolbar?.navigationIcon?.setColorFilter(ContextCompat.getColor(this, color)) /* 1 */
progressBar.indeterminateDrawable.setColorFilter(color, Mode.SRC_IN) /* 2 */
我尝试使用BlendMode
和PorterDuff.Mode
参数(例如drawable.setColorFilter(color, BlendMode.SRC_ATOP, PorterDuff.Mode.SRC_ATOP)
)调用setColorFilter
方法,但导致运行时异常:
java.lang.NoClassDefFoundError: Failed resolution of:
Landroid/graphics/BlendMode;
因此,我们只能从SDK版本29开始使用BlendMode调用任何方法(它是在那里添加的)。我不得不创建带有Mode
参数的setColorFilter
。
DrawableCompat.setTint(drawable, color)
或者 直接在 xml 中为ImageView
等元素着色。 - Andy RessetTint() - Drawable的绘制内容将在绘制到屏幕之前与其色调混合。这类似于{@link #setColorFilter(int, PorterDuff.Mode)}。
- Andy Res