【问题标题】:programmatically update android Vector Drawable以编程方式更新android Vector Drawable
【发布时间】:2015-05-01 16:40:31
【问题描述】:

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

【问题讨论】:

  • 你有答案吗?
  • 您要么需要使用多个drawable,要么让单个drawable 成为动画。为什么不想使用 AnimatedVectorDrawable?
  • 发布您的自定义drawable。这将对我们有所帮助。
  • 请查看this答案。

标签: android android-vectordrawable


【解决方案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>

【讨论】:

    【解决方案2】:

    使用此library 直接访问内部元素。就是实现这个answer

    【讨论】:

      【解决方案3】:

      简而言之:

      1. 没有可以直接访问VectorDrawable 中的内部元素。
      2. AnimatedVectorDrawable 只能访问内部元素。
      3. 使用AnimatedVectorDrawable 模拟您需要的内容。

      长:

      1.您无权访问

      查看source code 中的VectorDrawable 将显示内部元素信息存储在内部private 状态类VectorDrawableState 中。 name 暴露内部元素的唯一方法是getTargetByName,但不幸的是它是包私有的(默认)——你不能使用它(除非你使用反射)。

      2。 AnimatedVectorDrawable 只有访问权限

      getTargetByName 只被AnimatedVectorDrawable 使用,我们可以通过方法的searching for usages 找到。

      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>
      

      动画.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); } 看起来你说如果我使用这个方法,那么理论上我可以在那个对象(“目标”)上执行一个对象动画改变颜色?你说我需要先mutate 对象是什么意思?
      • 如果您使用反射来获取getTargetByName,您将能够通过名称获取XML 中定义的元素。一个例子是 VFullPath 类型——它也是一个私有类。您将需要在 mFillColor 字段上再次使用反射来操作它(以更改颜色)。关于 mutate,您必须在可绘制对象本身上调用 mutate() - 这将创建内部状态的本地副本。在您这样做之前,所有相同的可绘制对象共享相同的支持数据以提高性能。
      • 谢谢@Eyal。这就说得通了。期待他们何时为此公开一个公共 API。我现在可以尝试这种反射黑客,但我现在使用带有 RapahelJS 的 Webview 作为解决方法。您是否弄乱了他们为 VectorDrawable 开发的支持库,看看这是否也适用? android.googlesource.com/platform/frameworks/support/+/master/…