为可绘制图形添加动画效果

试用 Compose 方式
Jetpack Compose 是推荐用于 Android 的界面工具包。了解如何在 Compose 中使用动画。
图 1. 带动画的可绘制对象。

在某些情况下,图片需要添加动画效果。如果您想显示由多张图片组成的自定义加载动画,或者希望图标在用户执行操作后变形,这会非常有用。Android 提供了两个用于为可绘制对象添加动画效果的选项。

第一个选项是使用 AnimationDrawable。这样,您就可以指定多个静态可绘制文件,一次显示一个文件,从而创建动画。第二个选项是使用 AnimatedVectorDrawable,它可让您为矢量可绘制对象的属性添加动画效果。

使用 AnimationDrawable

创建动画的一种方法是加载一系列可绘制资源,例如一卷电影。AnimationDrawable是此类可绘制动画的基础。

您可以使用 AnimationDrawable 类 API 在代码中定义动画帧,但使用列出组成动画的帧的单个 XML 文件来定义它们会更容易。此类动画的 XML 文件位于 Android 项目的 res/drawable/ 目录中。在此示例中,指令会给出动画中每一帧的顺序和时长。

XML 文件包含一个 <animation-list> 元素(作为根节点)和一系列子 <item> 节点(每个节点定义一个帧),即一个可绘制资源及其时长。下面是一个 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,动画会循环播放。

如果您在项目的 res/drawable/ 目录中将此 XML 另存为 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 尚未完全附加到窗口。如需立即播放动画而不需要使用互动,您可以通过 Activity 中的 onStart() 方法(当 Android 将视图显示在屏幕上时,系统会调用该方法)调用它。

如需详细了解 XML 语法以及可用的标记和属性,请参阅动画资源

使用 AnimatedVectorDrawable

矢量可绘制对象是一种可缩放且不会像素化或模糊的可绘制对象。借助 AnimatedVectorDrawable和用于实现向后兼容性的 AnimatedVectorDrawableCompat,您可以为矢量可绘制对象的属性添加动画效果,例如旋转或更改路径数据以将其变形为其他图片。

您通常可以在以下三个 XML 文件中定义动画矢量可绘制对象:

  • 一个矢量可绘制对象,<vector> 元素位于 res/drawable/ 中。
  • 一个动画矢量可绘制对象,在 res/drawable/ 中包含 <animated-vector> 元素。
  • 一个或多个对象 Animator,其中 <objectAnimator> 元素位于 res/animator/

添加动画效果的矢量可绘制对象可以为 <group><path> 元素的属性添加动画效果。<group> 元素定义一组路径或子组,<path> 元素定义要绘制的路径。

定义要添加动画效果的矢量可绘制对象时,请使用 android:name 属性为组和路径分配一个唯一名称,以便您可以从 Animator 定义中引用它们。例如:

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>

添加动画效果的矢量可绘制对象定义会按名称来引用矢量可绘制对象中的组和路径:

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 对象。下例中的第一个 Animator 会将目标组旋转 360 度:

res/animator/rotation.xml

<objectAnimator
    android:duration="6000"
    android:propertyName="rotation"
    android:valueFrom="0"
    android:valueTo="360" />

此示例中的第二个 Animator 会对矢量可绘制对象的路径进行变形。这些路径必须兼容变形:它们必须有相同数量的指令,而且每个指令都必须拥有相同数量的参数。

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

动画形式的矢量可绘制对象 (AVD) 预览

借助 Android Studio 中的动画形式的矢量可绘制对象工具,您可以预览动画形式的可绘制资源。此工具可帮助您在 Android Studio 中预览 <animation-list><animated-vector><animated-selector> 资源,让您可以更轻松地优化自定义动画。

用户在 Android Studio 中预览和播放动画
图 3. Android Studio 中的 Animated Vector Drawable 工具。

如需了解详情,请参阅 AnimatedVectorDrawable 的 API 参考文档。