以编程方式更新Android矢量图绘制(Vector Drawable)。

32

我有一个由9个矩形组成的VectorDrawable,这是在drawable文件夹中定义为XML格式。我将其设置为在xml中声明的ImageView的背景android:src="@drawable/squares00"。 我想在运行时通过编程方式更改一个或多个正方形的颜色。我知道可以使用VectorDrawable动画来实现此操作。但我想知道是否有更简单的方法在Java中访问我的VectorDrawable、更新其属性(设置一个或多个矩形的填充颜色),然后使图像背景更新为更新后的VectoDrawable。我的目标是Android API 21 (lollipop)


3
你有答案了吗? - Shreeshesh
你可以使用多个drawable或者将单个drawable设置为可动画。为什么不想使用AnimatedVectorDrawable呢? - Andrew Flynn
发布您的自定义可绘制资源。这将有助于我们。 - Hiren Dabhi
请查看此答案:https://dev59.com/ol8d5IYBdhLWcg3wsT0b#35738726 - Amit Vaghela
3个回答

24
简而言之:
1. 您无法直接访问VectorDrawable中的内部元素。 2. AnimatedVectorDrawable只能访问内部元素。 3. 使用AnimatedVectorDrawable来模拟您需要的效果。
详细说明:
1. 您无法访问内部元素。

我看到源代码VectorDrawable的内部元素信息是存储在一个内部VectorDrawableState状态类中的私有数据。唯一以名称方式公开内部元素的方法是getTargetByName,但不幸的是它是包私有(默认)的 - 除非您使用反射,否则无法使用它。

2. 只有AnimatedVectorDrawable可以访问

getTargetByName 只在 AnimatedVectorDrawable 中使用,我们可以通过 搜索该方法的用途 找到这一点。

3. 使用 AnimatedVectorDrawable

现在我们知道这是唯一可用的选项,例如,我们可以尝试以下方法将元素“rect2”的颜色从白色更改为黑色:

change_color.xml:

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="0"
        android:propertyName="fillColor"
        android:valueFrom="@color/white"
        android:valueTo="@color/black"/>
</set>

animation.xml:

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/vectordrawable" >
    <target
        android:name="rect2"
        android:animation="@anim/change_color" />
</animated-vector>

并使用此处描述的方法here

注意

如果以上仍不适用于您,您可以尝试以下操作:

  • 复制整个VectorDrawable并进行微调(未经测试)
  • 使用getTargetByName的反射来获取内部元素。您需要先确保对对象进行mutate

我看到你在VectorDrawable中提到的包私有方法:Object getTargetByName(String name) { return mVectorState.mVPathRenderer.mVGTargetsMap.get(name); }看起来你是说如果我使用这个方法,那么理论上我可以对该对象(“target”)执行对象动画以改变颜色?当你说我需要首先“mutate”对象时,你是什么意思? - Sam Edwards
1
如果您使用反射来获取getTargetByName,您将能够按名称获取在XML中定义的元素。一个例子是VFullPath类型 - 这也是一个私有类。您需要再次使用反射来操作mFillColor字段(以更改颜色)。关于mutate,您必须在可绘制对象本身上调用mutate() - 这将创建内部状态的本地副本。在此之前,所有相同的可绘制对象共享相同的后备数据以提高性能。 - Eyal Biran
谢谢@Eyal。这很有道理。期待他们公开API的时候。我现在可以尝试这个反射hack,但是现在使用RapahelJS的Webview作为解决方法。您是否尝试过他们正在开发的支持库,以查看它是否也适用于VectorDrawable?https://android.googlesource.com/platform/frameworks/support/+/master/v7/vectordrawable/ - Sam Edwards
请问您能否演示如何使用反射在VectorDrawable上更改特定路径的颜色? - android developer

1

使用这个可以直接访问内部元素。实现这个答案


1

尝试使用这个库https://github.com/devendroid/VectorChildFinder

val vector = VectorChildFinder(context, R.drawable.drawable_id, imageView)
vector.findPathByName("path_name").fillColor = Color.RED

<vector
    ...>

    <path
        android:name="path_name"
        android:fillColor="#000"
        android:pathData="..." />
</vector>

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