使用动画启动 Activity

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

Material Design 应用中的 Activity 转场通过运动和共同元素之间的变换,在不同状态之间提供视觉连接。您可以为进入和退出转场以及 Activity 之间共享元素的转场指定自定义动画。

图 1. 包含共享元素的转场。

  • 进入”转场决定 Activity 中的视图如何进入场景。例如,在 explode 进入转场中,视图从外部进入场景,然后飞入屏幕中心。
  • 退出”转场决定 Activity 中的视图如何退出场景。例如,在 explode 退出转场中,视图从中心向外退出场景。
  • 共享元素”转场决定在两个 Activity 之间共享的视图如何在这两个 Activity 之间进行转场。例如,如果两个 Activity 在不同位置和大小上显示同一张图片,changeImageTransform 共享元素转场会在这两个 Activity 之间平滑地平移和缩放图片。

Android 支持以下进入和退出转场:

  • explode:将视图移入场景中心或从场景中心移出。
  • slide:将视图从场景边缘之一移入或移出。
  • fade:通过更改视图的不透明度将其添加到场景或从场景中移除。

任何扩展 Visibility 类的转场都支持作为进入或退出转场。如需了解详情,请参阅 Transition 类的 API 参考文档。

Android 还支持以下共享元素转场:

  • changeBounds:动画化目标视图布局边界的变化。
  • changeClipBounds:动画化目标视图剪辑边界的变化。
  • changeTransform:动画化目标视图缩放和旋转的变化。
  • changeImageTransform:动画化目标图片大小和缩放的变化。

在应用中启用 Activity 转场后,进入和退出 Activity 之间会激活默认的交叉淡入淡出转场。

图 2. 包含一个共享元素的场景转场。

如需查看使用共享元素在 Activity 之间进行动画处理的示例代码,请参阅 ActivitySceneTransitionBasic

检查系统版本

Activity 转场 API 可在 Android 5.0(API 21)及更高版本上使用。为了保持与早期 Android 版本的兼容性,在使用这些功能的 API 之前,请先在运行时检查系统 版本

Kotlin

// Check if we're running on Android 5.0 or higher
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    // Apply activity transition
} else {
    // Swap without transition
}

Java

// Check if we're running on Android 5.0 or higher
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    // Apply activity transition
} else {
    // Swap without transition
}

指定自定义转场

首先,当您定义继承自 Material 主题的样式时,使用 android:windowActivityTransitions 属性启用窗口内容转场。您还可以在样式定义中指定进入、退出和共享元素转场。

<style name="BaseAppTheme" parent="android:Theme.Material">
  <!-- enable window content transitions -->
  <item name="android:windowActivityTransitions">true</item>

  <!-- specify enter and exit transitions -->
  <item name="android:windowEnterTransition">@transition/explode</item>
  <item name="android:windowExitTransition">@transition/explode</item>

  <!-- specify shared element transitions -->
  <item name="android:windowSharedElementEnterTransition">
    @transition/change_image_transform</item>
  <item name="android:windowSharedElementExitTransition">
    @transition/change_image_transform</item>
</style>

本示例中的 change_image_transform 转场定义如下:

<!-- res/transition/change_image_transform.xml -->
<!-- (see also Shared Transitions below) -->
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android">
  <changeImageTransform/>
</transitionSet>

changeImageTransform 元素对应于 ChangeImageTransform 类。如需了解详情,请参阅 Transition 的 API 参考文档。

要在代码中启用窗口内容转场,请调用 Window.requestFeature() 函数。

Kotlin

// Inside your activity (if you did not enable transitions in your theme)
with(window) {
    requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)

    // Set an exit transition
    exitTransition = Explode()
}

Java

// Inside your activity (if you did not enable transitions in your theme)
getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);

// Set an exit transition
getWindow().setExitTransition(new Explode());

要在代码中指定转场,请使用 Transition 对象调用以下函数:

setExitTransition()setSharedElementExitTransition() 函数定义调用 Activity 的退出转场。setEnterTransition()setSharedElementEnterTransition() 函数定义被调用 Activity 的进入转场。

为了获得完整的转场效果,您必须在调用 Activity 和被调用 Activity 上都启用窗口内容转场。否则,调用 Activity 会启动退出转场,但您随后会看到窗口转场(例如缩放或淡入淡出)。

要尽快开始进入转场,请在被调用 Activity 上使用 Window.setAllowEnterTransitionOverlap() 函数。这样可以实现更具戏剧性的进入转场。

使用转场启动 Activity

如果您启用转场并为某个 Activity 设置退出转场,则在您启动另一个 Activity 时,转场会如下所示地激活:

Kotlin

startActivity(intent,
              ActivityOptions.makeSceneTransitionAnimation(this).toBundle())

Java

startActivity(intent,
              ActivityOptions.makeSceneTransitionAnimation(this).toBundle());

如果您为第二个 Activity 设置进入转场,则在该 Activity 启动时,该转场也会激活。如需在启动另一个 Activity 时停用转场,请提供 null options bundle。

启动带共享元素的 Activity

要实现两个 Activity 之间带共享元素的屏幕转场动画,请执行以下操作:

  1. 在主题中启用窗口内容转场。
  2. 在样式中指定共享元素转场。
  3. 将转场定义为 XML 资源。
  4. 使用 android:transitionName 属性为两个布局中的共享元素指定通用名称。
  5. 使用 ActivityOptions.makeSceneTransitionAnimation() 函数。

Kotlin

// Get the element that receives the click event
val imgContainerView = findViewById<View>(R.id.img_container)

// Get the common element for the transition in this activity
val androidRobotView = findViewById<View>(R.id.image_small)

// Define a click listener
imgContainerView.setOnClickListener( {
    val intent = Intent(this, Activity2::class.java)
    // Create the transition animation - the images in the layouts
    // of both activities are defined with android:transitionName="robot"
    val options = ActivityOptions
            .makeSceneTransitionAnimation(this, androidRobotView, "robot")
    // Start the new activity
    startActivity(intent, options.toBundle())
})

Java

// Get the element that receives the click event
final View imgContainerView = findViewById(R.id.img_container);

// Get the common element for the transition in this activity
final View androidRobotView = findViewById(R.id.image_small);

// Define a click listener
imgContainerView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Intent intent = new Intent(this, Activity2.class);
        // Create the transition animation - the images in the layouts
        // of both activities are defined with android:transitionName="robot"
        ActivityOptions options = ActivityOptions
            .makeSceneTransitionAnimation(this, androidRobotView, "robot");
        // Start the new activity
        startActivity(intent, options.toBundle());
    }
});

对于在代码中生成的共享动态视图,请使用 View.setTransitionName() 函数在两个 Activity 中指定通用元素名称。

要在完成第二个 Activity 时反转场景转场动画,请调用 Activity.finishAfterTransition() 函数,而不是 Activity.finish()

启动带多个共享元素的 Activity

要在包含多个共享元素的两个 Activity 之间制作场景转场动画,请在两个布局中使用 android:transitionName 属性(或在两个 Activity 中使用 View.setTransitionName() 函数)定义共享元素,然后创建 ActivityOptions 对象,如下所示:

Kotlin

// Rename the Pair class from the Android framework to avoid a name clash
import android.util.Pair as UtilPair
...
val options = ActivityOptions.makeSceneTransitionAnimation(this,
        UtilPair.create(view1, "agreedName1"),
        UtilPair.create(view2, "agreedName2"))

Java

ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,
        Pair.create(view1, "agreedName1"),
        Pair.create(view2, "agreedName2"));