添加对预测返回动画的支持

使用系统返回 API 时,您可以选择接收应用内动画并支持自定义过渡。

视频 1:预测返回动画

选择启用后,您的应用会显示返回主屏幕、跨 Activity 和跨任务的动画。

您还可以将 Material Component 依赖项升级到 MDC Android 的 v1.10.0,以接收如下 Material Component 动画:

如需了解更多信息,请参阅 GitHub 上的 Material Component 开发者指南

该视频简要展示了使用 Android 设置应用进行跨 Activity 和返回主屏幕的预测返回动画示例。

  1. 在动画中,用户向后滑动以返回上一个设置屏幕,这是一个跨 Activity 动画的示例。
  2. 现在,在上一屏幕上,用户开始第二次向后滑动,显示带有壁纸的主屏幕预览,这是一个返回主屏幕动画的示例。
  3. 用户继续向右滑动,显示窗口缩小到主屏幕图标的动画。
  4. 用户现已完全返回主屏幕。

详细了解如何添加对预测返回手势的支持

添加自定义应用内过渡和动画

您可以使用预测返回手势创建自定义应用内属性动画和过渡、自定义跨 Activity 动画以及自定义跨 Fragment 动画。

使用 Progress API 添加自定义过渡

借助 AndroidX Activity 1.8.0-alpha01 或更高版本,您可以使用 Predictive Back Progress API 开发应用中预测返回手势的自定义动画。Progress API 有助于为视图添加动画,但在为 Fragment 之间的过渡添加动画时存在局限性。在 OnBackPressedCallback 中,我们引入了 handleOnBackProgressedhandleOnBackCancelledhandleOnBackStarted 方法,以便在用户向后滑动时为对象添加动画。如果您需要自定义系统提供的默认动画或 Material Component 动画之外的内容,请使用这些方法。

我们预计大多数应用将使用向后兼容的 AndroidX API,但 Android 14 开发者预览版 1 及更高版本中也提供了 OnBackAnimationCallback 接口中的类似平台 API 供测试。

将 Progress API 与 AndroidX Transitions 结合使用

Progress API 可与 AndroidX Transitions 1.5.0-alpha01 或更高版本在 Android 14 及更高版本上配合使用,以创建预测返回过渡。

  1. 使用 TransitionManager#controlDelayedTransition 而不是 beginDelayedTransition 来在用户向后滑动时播放过渡。
  2. handleOnBackStarted 中创建过渡。
  3. 通过将 currentFractionBackEvent.progress(其显示用户向后滑动的距离)相关联,在 handleOnBackProgressed 中将过渡与返回事件一起播放。
  4. 用户在 handleOnBackPressed 中提交返回手势后,完成过渡。
  5. 最后,在 handleOnBackCancelled 中重置过渡状态。

以下视频、Kotlin 代码和 XML 演示了使用 OnBackPressedCallback 实现的两个框之间的自定义过渡:

    class MyFragment : Fragment() {

    val transitionSet = TransitionSet().apply {
        addTransition(Fade(Fade.MODE_OUT))
        addTransition(ChangeBounds())
        addTransition(Fade(Fade.MODE_IN))
    }
    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val callback = object : OnBackPressedCallback(enabled = false) {

            var controller: TransitionSeekController? = null

            @RequiresApi(34)
            override fun handleOnBackStarted(backEvent: BackEvent) {
                // Create the transition
                controller = TransitionManager.controlDelayedTransition(
                    binding.card,
                    transitionSet
                )
                changeTextVisibility(ShowText.SHORT)
            }

            @RequiresApi(34)
            override fun handleOnBackProgressed(backEvent: BackEvent) {
                // Play the transition as the user swipes back
                if (controller?.isReady == true) {
                    controller?.currentFraction = backEvent.progress
                }
            }

            override fun handleOnBackPressed() {
                // Finish playing the transition when the user commits back
                controller?.animateToEnd()
                this.isEnabled = false
            }

            @RequiresApi(34)
            override fun handleOnBackCancelled() {
                // If the user cancels the back gesture, reset the state
                transition(ShowText.LONG)
            }
        }

        binding.shortText.setOnClickListener {
            transition(ShowText.LONG)
            callback.isEnabled = true
        }

        this.requireActivity().onBackPressedDispatcher.addCallback(callback)
    }

    private fun transition(showText: ShowText) {
        TransitionManager.beginDelayedTransition(
            binding.card,
            transitionSet
        )
        changeTextVisibility(showText)
    }

    enum class ShowText { SHORT, LONG }
    private fun changeTextVisibility(showText: ShowText) {
        when (showText) {
            ShowText.SHORT -> {
                binding.shortText.isVisible = true
                binding.longText.isVisible = false
            }
            ShowText.LONG -> {
                binding.shortText.isVisible = false
                binding.longText.isVisible = true
            }
        }
    }
}
  
<?xml version="1.0" encoding="utf-8"?>
...
    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/card"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        ...>

        <TextView
            android:id="@+id/short_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            ... />

        <TextView
            android:id="@+id/long_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="gone"
            .../>

    </androidx.constraintlayout.widget.ConstraintLayout>

在使用预测返回过渡时,请记住以下几点:

  • 使用 isSeekingSupported 检查过渡是否支持预测返回。
  • 为您的自定义过渡重写 isSeekingSupported 以返回 true。
  • 每个动画创建一个控制器。
  • 预测返回过渡支持 AndroidX 过渡,但不支持框架过渡。请从框架过渡迁移,转而使用 Animator 和 AndroidX 过渡。
  • 预测返回过渡在运行 Android 14 及更高版本的设备上受支持,且不向后兼容。
  • 使用 XML 场景创建的过渡也受支持。在 handleOnBackStarted 中,将 TransitionSeekController 设置为 TransitionManager.createSeekController 的结果,而不是 controlDelayedTransition 的结果。

在 Android 14 及更高版本上添加自定义 Activity 过渡

为了确保自定义 Activity 过渡在 Android 14 及更高版本上支持预测返回,您可以使用 overrideActivityTransition 而不是 overridePendingTransition。这意味着当用户向后滑动时,过渡动画会播放。

为了说明其工作原理,假设 Activity B 在返回堆栈中位于 Activity A 的顶部。您可以按以下方式处理自定义 Activity 动画:

  • 在 Activity B 的 onCreate 方法中调用打开或关闭过渡。
  • 当用户导航到 Activity B 时,使用 OVERRIDE_TRANSITION_OPEN。当用户滑动以导航回 Activity A 时,使用 OVERRIDE_TRANSITION_CLOSE
  • 在指定 OVERRIDE_TRANSITION_CLOSE 时,enterAnim 是 Activity A 的进入动画,而 exitAnim 是 Activity B 的退出动画。

为 Fragment 添加预测返回支持

使用 Fragment 实现预测返回时,有两种方法。

使用现有 API

我们建议您使用现有 API。这些 API 允许您从屏幕边缘滑动,通过手势操纵 Animator 或 AndroidX 过渡。您是否将手势移过阈值决定了它是完成并返回到上一个 Fragment,还是取消并停留在当前 Fragment。有关更多信息,请参阅使用动画在 Fragment 之间导航

请记住以下因素:

  • 导入 Transitions 1.5.0 或更高版本以及 Fragments 1.7.0 或更高版本。Fragment 中的预测返回支持很大程度上依赖于 Transitions 能够寻找动画,这只有在 Transitions 1.5.0 或更高版本中才可能实现。
  • 使用 Fragment(通过 FragmentManager导航组件)来处理返回堆栈。如果您管理自己的返回堆栈,则不支持预测返回。请从 FragmentManager 不知道的返回堆栈中迁移。
  • 某些库包含预测返回支持。请务必查看文档。
  • 支持 Animator 类和 AndroidX Transition 库。
  • 不支持 Animation 类和框架 Transition 库。
  • 预测动画仅适用于运行 Android 14 或更高版本的设备。

在以下情况下使用预测返回跨 Fragment:

某些Material Motion1.12.02-alpha02 或更高版本开始支持预测返回,包括 MaterialFadeThroughMaterialSharedAxisMaterialFade。请注意,MaterialContainerTransform 不支持预测返回。

使用回调

您可以使用回调创建跨 Fragment 过渡,但使用回调时存在一个已知限制,即用户在向后滑动时无法看到上一个 Fragment。要创建与预测返回设计指南相符的跨 Fragment 共享元素过渡,请执行以下操作:

创建 OnBackPressedCallback。在 handleOnBackProgressed 中,缩放和移动 Fragment。然后从返回堆栈中弹出。接下来,在回调外部使用 setSharedElementReturnTransition 运行共享元素过渡。

如需了解更多信息,请参阅 GitHub 上的代码示例

要求

使用下表了解 targetSdkVersioncompileSdkVersion、设备版本、依赖项、清单标志和 Fragment 标志控制的内容。此表指的是代码要求。

类别 动画 compileSdk targetSdk 设备版本 android:enableOnBackInvokedCallback 依赖项
系统动画 返回主屏幕 33 任意 35 TRUE
跨 Activity 34 任意 35 TRUE
跨任务 34 任意 35 TRUE
平台 自定义跨 Activity 34 任意 35 TRUE
Progress API 平台 34 任意 34 TRUE
Material Components 底部抽屉式导航栏 34 任意 34 TRUE Material Component 1.10.0
侧边抽屉式导航栏 34 任意 34 TRUE Material Component 1.10.0
导航抽屉式菜单 34 任意 34 TRUE Material Component 1.10.0
搜索 34 任意 34 TRUE Material Component 1.10.0
Jetpack 动画 自定义 AndroidX 跨 Fragment 34 任意 34 TRUE AndroidX Fragment 1.7
自定义 AndroidX 过渡 34 任意 34 TRUE AndroidX Transition 1.5
Progress API Jetpack 34 任意 34 TRUE AndroidX Activity 1.8

其他资源