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

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

视频 1:预测性后退动画

选择加入后,您的应用将显示返回主屏幕、跨活动和跨任务的动画。

您还可以将您的 Material 组件依赖项升级到 MDC Android 的 v1.10.0 版本,以接收以下 Material 组件动画

请参阅 GitHub 上的 Material 组件开发者指南,了解更多信息。

该视频简要演示了使用 Android 设置应用进行跨活动和返回主屏幕的预测性后退动画。

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

了解有关如何 添加对预测性后退手势的支持 的更多信息。

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

您可以使用预测性后退手势创建自定义应用内属性动画和过渡、自定义跨活动动画和自定义跨片段动画。

使用 Progress API 添加自定义过渡

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

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

将 Progress API 与 AndroidX Transitions 一起使用

在 Android 14 及更高版本上,Progress API 可与 AndroidX Transitions 1.5.0-alpha01 或更高版本一起使用以创建预测性后退过渡。

  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 及更高版本上添加自定义活动过渡

为了确保自定义活动过渡在 Android 14 及更高版本上支持预测性后退,您可以使用 overrideActivityTransition 代替 overridePendingTransition。这意味着过渡动画将在用户向后滑动时播放。

为了举例说明其工作原理,想象一下 Activity B 在返回堆栈中位于 Activity A 上方的情况。您将按以下方式处理自定义活动动画

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

添加对使用片段的预测式返回的支持

在使用片段实现预测式返回时,有两种方法。

使用现有 API

我们建议您使用现有 API。这些 API 允许您从屏幕边缘滑动来使用手势操作您的 Animator 或 Androidx 转场动画。手势是否超过阈值将决定操作是否完成并返回到上一个片段,或者操作是否取消并停留在当前片段。更多信息,请参见 使用动画在片段之间导航

请记住以下因素

  • 导入 Transitions 1.5.0 或更高版本和 Fragments 1.7.0 或更高版本。Fragments 中大部分预测式返回支持依赖于 Transitions 能够搜索动画,而这只有在 Transitions 1.5.0 或更高版本中才有可能。
  • 使用 Fragments,以及 FragmentManager导航组件 来处理返回栈。如果您自己管理返回栈,则不支持预测式返回。请迁移离开 FragmentManager 未知的返回栈。
  • 一些库包含预测式返回支持。请查看文档以确保。
  • 支持 Animator 类和 AndroidX Transition 库。
  • 不支持 Animation 类和框架 Transition 库。
  • 预测式动画仅适用于运行 Android 14 或更高版本的设备。

在以下情况下使用跨片段的预测式返回

1.12.02-alpha02 或更高版本开始,一些 Material 运动 支持预测式返回,包括 MaterialFadeThroughMaterialSharedAxisMaterialFade。请注意 MaterialContainerTransform 不支持预测式返回。

使用回调

您可以使用回调创建跨片段转场动画,但是使用回调时存在一个已知的限制,即用户在向后滑动时看不到上一个片段。要创建与预测式返回 设计指南 相对应的跨片段共享元素转场动画,请执行以下操作

创建一个 OnBackPressedCallback。在 handleOnBackProgressed 中,缩放和平移片段。然后从返回栈中弹出。接下来,在回调之外使用 setSharedElementReturnTransition 运行共享元素转场动画。

更多信息,请参见 GitHub 上的 代码示例

要求

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

类别 动画 compileSdk targetSdk 设备版本 android:enableOnBackInvokedCallback 依赖项
系统动画 返回主页 33 任意 35 TRUE
跨活动 34 任意 35 TRUE
跨任务 34 任意 35 TRUE
平台 自定义跨活动 34 任意 35 TRUE
Progress API 平台 34 任意 34 TRUE
Material 组件 底部表单 34 任意 34 TRUE Material 组件 1.10.0
侧边表单 34 任意 34 TRUE Material 组件 1.10.0
导航抽屉 34 任意 34 TRUE Material 组件 1.10.0
搜索 34 任意 34 TRUE Material 组件 1.10.0
Jetpack 动画 自定义 AndroidX 跨片段 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

其他资源