动画化 Drawable 图形

尝试 Compose 方式
Jetpack Compose 是推荐用于 Android 的 UI 工具包。了解如何在 Compose 中使用动画。
图 1. 动画化 Drawable。

在某些情况下,需要动画化图像。如果你想显示由多个图像组成的自定义加载动画,或者想让图标在用户操作后变形,这会很有用。Android 提供了两种动画化 Drawable 的选项。

第一种选项是使用 AnimationDrawable。这允许你指定多个静态drawable 文件,这些文件逐一显示以创建动画。第二种选项是使用 AnimatedVectorDrawable,它可以让你动画化矢量 Drawable 的属性。

使用 AnimationDrawable

一种创建动画的方式是加载一系列 Drawable 资源,就像一卷胶片一样。 AnimationDrawable 类是此类 Drawable 动画的基础。

你可以使用 AnimationDrawable 类 API 在代码中定义动画的帧,但更简单的方式是使用一个 XML 文件来定义,该文件列出了构成动画的帧。此类动画的 XML 文件应放在 Android 项目的 res/drawable/ 目录中。在这种情况下,说明会给出动画中每个帧的顺序和持续时间。

XML 文件包含一个 <animation-list> 元素作为根节点,以及一系列子 <item> 节点,每个节点定义一个帧——一个 Drawable 资源及其持续时间。以下是 Drawable 动画的 XML 文件示例:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>

此动画运行三帧。将列表的 android:oneshot 属性设置为 true 会使其循环一次,然后在最后一帧停止并保持。如果你将 android:oneshot 设置为 false,动画将循环播放。

如果你将此 XML 保存为项目 res/drawable/ 目录中的 rocket_thrust.xml,可以将其添加为 View 的背景图片,然后调用 start() 使其播放。以下是一个 activity 示例,其中动画被添加到 ImageView 中,并在屏幕被触摸时进行动画播放:

Kotlin

private lateinit var rocketAnimation: AnimationDrawable

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.main)

    val rocketImage = findViewById<ImageView>(R.id.rocket_image).apply {
        setBackgroundResource(R.drawable.rocket_thrust)
        rocketAnimation = background as AnimationDrawable
    }

    rocketImage.setOnClickListener({ rocketAnimation.start() })
}

Java

AnimationDrawable rocketAnimation;

public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
  rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
  rocketAnimation = (AnimationDrawable) rocketImage.getBackground();

  rocketImage.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        rocketAnimation.start();
      }
  });
}

值得注意的是,对 AnimationDrawable 调用 start() 方法不能在 ActivityonCreate() 方法期间进行,因为 AnimationDrawable 尚未完全附加到窗口。要立即播放动画,而无需交互,可以从 ActivityonStart() 方法中调用它,该方法在 Android 使视图在屏幕上可见时调用。

有关 XML 语法以及可用标签和属性的更多信息,请参阅动画资源

使用 AnimatedVectorDrawable

矢量 Drawable 是一种 Drawable 类型,可以在不像素化或模糊的情况下进行缩放。AnimatedVectorDrawable 类(以及用于向后兼容的 AnimatedVectorDrawableCompat)允许你动画化矢量 Drawable 的属性,例如旋转它或更改路径数据以将其变形为不同的图像。

你通常在三个 XML 文件中定义动画矢量 Drawable:

  • res/drawable/ 中包含 <vector> 元素的矢量 Drawable。
  • res/drawable/ 中包含 <animated-vector> 元素的动画矢量 Drawable。
  • res/animator/ 中包含 <objectAnimator> 元素的一个或多个对象动画器。

动画矢量 Drawable 可以动画化 <group><path> 元素的属性。<group> 元素定义了一组路径或子组,<path> 元素定义了要绘制的路径。

定义要动画化的矢量 Drawable 时,使用 android:name 属性为组和路径分配唯一名称,以便可以在动画器定义中引用它们。例如:

res/drawable/vectordrawable.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="64dp"
    android:width="64dp"
    android:viewportHeight="600"
    android:viewportWidth="600">
    <group
        android:name="rotationGroup"
        android:pivotX="300.0"
        android:pivotY="300.0"
        android:rotation="45.0" >
        <path
            android:name="v"
            android:fillColor="#000000"
            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
    </group>
</vector>

动画矢量 Drawable 定义通过名称引用矢量 Drawable 中的组和路径:

res/drawable/animatorvectordrawable.xml

<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
  android:drawable="@drawable/vectordrawable" >
    <target
        android:name="rotationGroup"
        android:animation="@animator/rotation" />
    <target
        android:name="v"
        android:animation="@animator/path_morph" />
</animated-vector>

动画定义代表 ObjectAnimatorAnimatorSet 对象。本例中的第一个动画器将目标组旋转 360 度:

res/animator/rotation.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
  <objectAnimator
      android:duration="6000"
      android:propertyName="rotation"
      android:valueFrom="0"
      android:valueTo="360" />
</set>

本例中的第二个动画器将矢量 Drawable 的路径从一种形状变形为另一种形状。路径必须兼容才能变形:它们必须具有相同数量的命令以及每个命令相同数量的参数。

res/animator/path_morph.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="3000"
        android:propertyName="pathData"
        android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
        android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
        android:valueType="pathType" />
</set>

以下是生成的 AnimatedVectorDrawable

图 2. 一个 AnimatedVectorDrawable

Animated Vector Drawable (AVD) 预览

Android Studio 中的 Animated Vector Drawable 工具允许你预览动画 Drawable 资源。此工具可帮助你在 Android Studio 中预览 <animation-list><animated-vector><animated-selector> 资源,并使自定义动画更容易完善。

User previewing and playing an animation inside Android Studio
图 3. Android Studio 中的 Animated Vector Drawable 工具。

有关详细信息,请参阅 AnimatedVectorDrawable 的 API 参考。