在Android中以编程方式更改矢量图形的填充颜色

56

我希望能够在Android程序中以编程方式编辑矢量文件的填充颜色。

在xml文件中,我可以使用属性android:fillColor设置颜色,但我希望在运行时更改颜色。

有任何示例可供参考吗?谢谢。


你好,你找到解决方案了吗?我也遇到了同样的问题。 - iMDroid
1
您可以使用XML中的android:tint或在运行时使用setColorFilter更改矢量文件的颜色。 - Sascha K.
1
https://dev59.com/GlsW5IYBdhLWcg3w8rD2#47174073 - Fakhar
博客完整答案:http://emmav.me/posts/2015-nov-29-dynamic-svg-colours/ - AZ_
9个回答

54

这篇文章正是您需要的。感谢@emmaguy,本文作者。我只是在其基础上加入了完整支持Support Library 23.4+,这使得你可以停止在运行时生成png文件:

 // Gradle Plugin 2.0+  
 android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
   }  
 } 

如果这行代码设置在你的Activity或Application的onCreate方法中:

AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
你不仅可以在 TextView、ToggleButton 等中使用 `srcCompat`,还可以在其他属性中使用 SVG,比如 `drawableLeft`、`background` 等。如果在选择器上使用也是可以的。
需要注意的是,我修改了代码,使用了 `VectorDrawableCompat.create` 来代替 `ResourcesCompat.getDrawable`。否则,它将无法工作并抛出 `org.xmlpull.v1.XmlPullParserException: Binary XML file line #2: invalid drawable tag vector` 异常。

Medium 文章内容:

首先,我们为两种吊坠创建属性,这样我们就可以更改它们的颜色:
<declare-styleable name="ChristmasTree">
    <attr name="bauble_round" format="color" />
    <attr name="bauble_small" format="color" />
</declare-styleable>

然后,在 VectorDrawable 中,将我们想要动态更改的部分设置为使用这些属性:

<path
    android:fillColor="?attr/bauble_round"
    android:pathData="...." />
<path
    android:fillColor="?attr/bauble_small"
    android:pathData="...." />
...

创建主题并设置你想使用的颜色:

<style name="UpdatedScene" parent="DefaultScene">
    <item name="bauble_round">#db486e</item>
    <item name="bauble_small">#22c7f7</item>
</style>

<style name="DefaultScene">
    <item name="bauble_round">#fec758</item>
    <item name="bauble_small">#f22424</item>
</style>

将可绘制对象用于ImageView中:

final ContextThemeWrapper wrapper = new ContextThemeWrapper(this, R.style.DefaultScene);
final Drawable drawable = VectorDrawableCompat.create(getResources(), R.drawable.christmas, wrapper.getTheme());
imageView.setImageDrawable(drawable);

就是这样!如果你想要改变颜色,只需设置不同的主题,你的可绘制对象就会更新。 查看 GitHub repo 以获取完整示例。


您也可以通过attr从ResourcesCompat.getDrawable(getResources(), R.drawable.ic, getTheme())获取带有颜色的Drawable。 - Mohamd Ali
这对于少量状态来说是可以的,但如果我想在动画期间每帧更新怎么办?例如参考 https://dev59.com/r3E85IYBdhLWcg3wx2n2#14467625 - hmac
1
请注意:仔细阅读文档 setcompatvectorfromresourcesenabled。"此功能默认为禁用状态,因为启用它可能会导致内存使用问题。" 祝编码愉快。 - Rhony
1
由于在API < 21中无法在fillColor属性上使用像?attr/colorPrimary这样的值,因此此方法不适用于该版本。 - rion18
1
@AlanNelson 你可以通过以下方式实现:final Resources.Theme theme = getResources().newTheme(); theme.applyStyle(R.style.BaubleRound, false); - saiyancoder
显示剩余5条评论

26

如果您想改变整个颜色,则可以应用PorterduffColorFilter。 但是这不适用于单个<path>。 仅适用于整个可绘制对象。

public void applyThemeToDrawable(Drawable image) {
    if (image != null) {
        PorterDuffColorFilter porterDuffColorFilter = new PorterDuffColorFilter(Color.BLUE,
                PorterDuff.Mode.SRC_ATOP);

        image.setColorFilter(porterDuffColorFilter);
    }
}

VectorDrawable扩展了Drawable类。 查看文档


4
有没有其他解决方案可以仅为单个<path>上色? - Sascha K.
这个答案 中发现,我猜你不能以编程方式更改单个路径颜色。至少不能完全随机地更改颜色,只能使用预定义的 XML 转换来设置固定集合。 - AlbAtNf
1
您可以将路径拆分为单独的图像,叠加这些视图,然后在各个视图上设置过滤器。虽然不是所有情况下都是理想的选择,但对于某些情况来说是可以接受的。 - Edward van Raak
这是我们现在所做的,但在问题被提出时没有考虑到。但请记住,每次拆分都会使内存使用量翻倍。对于大多数情况来说并不是什么大问题,但有时可能很重要。 - AlbAtNf

18

setColorFilter() 方法添加到您的图像内容矢量中(已在api级别8中添加),如下所示:

imgshare = (Imageview) findviewbyId(R.id.imageshare);
imgshare.setColorFilter(color);

对于color,确保不直接使用R.color.value,需调用getColor(R.color.value) - Adam Johns

1

button.setColorFilter(getResources().getColor(R.color.YOUR_COLOR));

例子:

dislikeBtn.setColorFilter(getResources().getColor(R.color.grey));


1

这些答案都不能在运行时更改可绘制对象中矢量路径的颜色。实际上,我仍然没有弄清楚,但我认为这个答案将帮助很多只是想在运行时创建和绘制简单形状的人。

我试图创建一个自定义边框Mvvm绑定,以在运行时自定义按钮的边框和填充颜色。有一段时间,我试图修改Android可绘制对象来实现这一点,但发现这是不可能的。最终我找到了如何使用GradientDrawable做到这一点。

我在C#中使用Xamarin.Android,所以它看起来与Java略有不同。

GradientDrawable gd = new GradientDrawable();
gd.SetColor(Color.Red);
gd.SetCornerRadius(10);

gd.SetStroke(3, Color.White);

view.Background = gd;

1
这是对我有效的方法:
VectorDrawableCompat vd = VectorDrawableCompat.create(getResources(),your_drawable_res_id,getContext().getTheme());
vd.setTint(Color.red);
imageview.setImageDrawable(vd);

0
只需使用:
imageView.setColorFilter(ContextCompat.getColor(context, R.color.white), PorterDuff.Mode.SRC_IN)

-1

要更改向量的颜色,请不要更改fillColor。相反,以编程方式更改色调,这将达到相同的效果并节省大量时间!请参见这里的答案


-1

对于那些寻找答案的人,当您的矢量图具有2个或更多<path>,或者您只想保持描边颜色与填充颜色不同:

我认为没有一种方法可以在编程时仅更改矢量的fillColor而忽略strokeColor(tint会同时修改两者)。

我通过创建3个副本来解决了这个问题,每个副本都在.xml中定义了不同的颜色,然后在kotlin中,我只设置了正确的矢量资产副本。 例如: view.setBackgroundResource(R.drawable.myVectorColor1)

view.setBackgroundResource(R.drawable.myVectorColor2)


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