添加对内置和自定义预测性返回动画的支持

如果您已将应用迁移到新的系统返回 API,可以执行以下操作: 选择启用预测性返回,以自动接收应用内消息 还支持自定义转场效果。

添加对内置应用内动画的支持

视频:预测性返回动画

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

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

如需了解详情,请参阅 GitHub 上的 Material 组件开发者指南

该视频展示了使用 Android 的“设置”应用实现的跨 activity 和“返回主屏幕”预测性返回动画的简短示例。

  1. 在动画中,用户滑回先前的“设置”界面,这是一个跨 activity 动画示例。
  2. 现在,在上一个界面上,用户又开始再滑动一次,系统会显示主屏幕及壁纸的预览,即“返回主屏幕”动画的示例。
  3. 用户继续向右滑动,此时系统显示了窗口如何缩小为主屏幕上的图标的动画。
  4. 用户现已完全返回主屏幕。

详细了解如何支持预测性返回

添加自定义应用内转场效果和动画

您可以使用 Progress API 和自定义跨 activity 动画方法 overrideActivityTransition 创建自定义应用内属性动画和转场效果。

使用 Progress API 添加自定义转场效果

借助 AndroidX Activity 1.8.0-alpha01 或更高版本,您可以使用预测性返回进度 API 为应用中的预测性返回手势开发自定义动画。在 OnBackPressedCallback 中,我们引入了 handleOnBackProgressedhandleOnBackCancelledhandleOnBackStarted 方法,以便在用户滑回时为对象添加动画效果。如果您需要实现的效果在自定义程度上超过了新系统动画或 Material 组件动画提供的默认动画,请使用这些方法。

我们希望大多数应用都使用向后兼容的 AndroidX API,但 OnBackAnimationCallback 接口中也有类似的平台 API 可用于在 Android 14 开发者预览版 1 及更高版本中进行测试。

将 Progress API 与 AndroidX 转场效果搭配使用

在 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 转场效果支持预测性返回转换,但框架转场效果不支持。我们建议不要使用框架转场效果。
  • 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 的退出动画。