以编程方式更改可绘制对象的颜色

205

我试图通过代码更改白色标记图像的颜色。我已经阅读了下面的代码应该会更改颜色,但是我的标记仍然是白色。

Drawable.setColorFilter( 0xffff0000, Mode.MULTIPLY )

我错过了什么吗?有没有其他方法可以更改位于我的“res”文件夹中的可绘制对象的颜色?


接受的答案对我没用,我使用了这个答案 - shyam.y
我认为这里所有的答案都改变了背景颜色,但没有改变图像的颜色。我是对的吗?有人能告诉我吗?我尝试了这里所有的解决方案,还在stackoverflow上找到了同样的问题,但它们只在我的情况下改变了背景颜色。所以我认为,我们只能改变背景颜色,而不能改变图像的颜色。我是对的吗? - Shirish Herwade
检查这个答案:https://dev59.com/MJPfa4cB1Zd3GeqPHsiH#66479081 - Anis LOUNIS aka AnixPasBesoin
20个回答

349

试试这个:

Drawable unwrappedDrawable = AppCompatResources.getDrawable(context, R.drawable.my_drawable); 
Drawable wrappedDrawable = DrawableCompat.wrap(unwrappedDrawable);
DrawableCompat.setTint(wrappedDrawable, Color.RED);    

使用 DrawableCompat 很重要,因为它在 API 22 及之前的设备上提供了向后兼容性和错误修复。


嗯,颜色仍然是白色。这可能与hello mapview的OverlayItems类有关,可能会导致问题吗?它是来自我的res文件夹的常规可绘制对象,没有什么特别的... - Johan
31
如果你希望它能够适用更广泛的源颜色,那么你可能更喜欢使用PorterDuff.Mode.SRC_IN。 - Lorne Laliberte
PorterDuff.Mode.MULTIPLY 对我没有产生任何变化(透明背景的黑色星形)。我使用 PorterDuff.Mode.SRC_ATOP 来为实际位图上色。 - Viktor Petrovski
1
PorterDuffColorFilter 构造函数采用 ARGB 颜色格式。 - RichX
3
使用#mutate()方法对可绘制对象进行变异将会很有趣,这样可以避免与任何其他可绘制对象共享其状态,否则如果重复使用该可绘制对象可能会出现颜色错误。 - Ricard
显示剩余2条评论

164

您可以尝试使用此方法将SVG矢量绘图转换为可绘制的格式

DrawableCompat.setTint(
    DrawableCompat.wrap(myImageView.getDrawable()),
    ContextCompat.getColor(context, R.color.another_nice_color)
);

7
我见过的SVG最好的方式。 - apSTRK
1
虽然两种方法都可以,但我更喜欢这个。使用这个方法,我不必担心要设置哪个drawable,因为我已经得到了一个可用的。而且它还向后兼容,非常棒! - usernotnull
1
最佳答案,当什么都不起作用时,物联网工作得像魅力一样!非常感谢!注意:当您在imageView / AppCompatImageView中拥有xml drawable时,它也适用。 - Sjd
1
如何以编程方式删除它? - Hardik Joshi
3
文档中说:*要清除色调,请将null传递给Drawable#setTintList(ColorStateList)*。 - arekolek
显示剩余3条评论

37

你可能需要在drawable上调用mutate(),否则所有图标都会受到影响。

Drawable icon = ContextCompat.getDrawable(getContext(), R.drawable.ic_my_icon).mutate();
TypedValue typedValue = new TypedValue();
getContext().getTheme().resolveAttribute(R.attr.colorIcon, typedValue, true);
icon.setColorFilter(typedValue.data, PorterDuff.Mode.SRC_ATOP);

1
你的回答真正令人难以置信的是 mutate(),这正是我在寻找的。谢谢。 - Adham Gamal

34

您可以尝试使用setColorFilter()来为ImageView进行调整。

imageView.setColorFilter(ContextCompat.getColor(context, R.color.colorWhite));

22

在Android 5.+的Lollipop上,另一种方法是为位图可绘制对象设置色彩,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_back"
    android:tint="@color/red_tint"/>

如果您希望在可绘图对象上使用有限数量的颜色,则此方法适用于您。 请查看我的博客文章以获取更多信息


2
不错!顺便说一下,这在Lollipop之前的版本上也可以正常工作。(我刚用minSdkVersion 16和Android 4.1.1设备测试了一下。) - Jonik
当以这种方式创建位图时,它不会像使用android:background="..."时那样拉伸以适应布局。非常奇怪! - Prince
我认为这是因为你没有在这里创建一个九宫格。 - MinceMan
抱歉,此页面不存在 =( - Linh
@Jonik,你提供的问题答案与此问题无关。这个问题是要求改变Drawable的颜色,而不是ImageView。 - Antony.H

13
我已经编写了一个通用函数,您可以通过传递上下文、图标ID(drawable/mipmap)以及需要的新颜色来使用它。
该函数返回一个可绘制对象。
public static Drawable changeDrawableColor(Context context,int icon, int newColor) {
    Drawable mDrawable = ContextCompat.getDrawable(context, icon).mutate(); 
    mDrawable.setColorFilter(new PorterDuffColorFilter(newColor, PorterDuff.Mode.SRC_IN)); 
    return mDrawable;
} 

changeDrawableColor(getContext(),R.mipmap.ic_action_tune, Color.WHITE);

10

这对我有用。确保在颜色代码的0x和"ff"之间加上。像这样0xff2196F3

Drawable mDrawable = ContextCompat.getDrawable(MainActivity.this,R.drawable.ic_vector_home);
                    mDrawable.setColorFilter(new
                            PorterDuffColorFilter(0xff2196F3,PorterDuff.Mode.SRC_IN));

嗨@Bek,欢迎来到stackoverflow。如果这对您有用,包含一个jsfiddle最小解决方案将非常有帮助,以便展示它。这将有助于提问者正确理解问题。 - Arjun Chaudhary

10

你可以尝试使用ColorMatrixColorFilter,因为你的关键颜色是白色:

// Assuming "color" is your target color
float r = Color.red(color) / 255f;
float g = Color.green(color) / 255f;
float b = Color.blue(color) / 255f;

ColorMatrix cm = new ColorMatrix(new float[] {
        // Change red channel
        r, 0, 0, 0, 0,
        // Change green channel
        0, g, 0, 0, 0,
        // Change blue channel
        0, 0, b, 0, 0,
        // Keep alpha channel
        0, 0, 0, 1, 0,
});
ColorMatrixColorFilter cf = new ColorMatrixColorFilter(cm);
myDrawable.setColorFilter(cf);

6

对于使用 Kotlin 的开发者,提供一个简单的扩展函数:

fun Drawable.tint(context: Context,  @ColorRes color: Int) {
    DrawableCompat.setTint(this, context.resources.getColor(color, context.theme))
}

然后只需执行
background.tint(context, R.color.colorPrimary)

6
与被接受的答案相同,但是有一个更简单的便捷方法:
val myDrawable = ContextCompat.getDrawable(context, R.drawable.my_drawable)
myDrawable.setColorFilter(Color.GREEN, PorterDuff.Mode.SRC_IN)
setCompoundDrawablesWithIntrinsicBounds(myDrawable, null, null, null)

注意,此处的代码是使用 Kotlin 编写的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接