添加对预测后退手势的支持

图 1. 手机上预测后退手势外观和感觉的模型

Android 14(API 级别 34)添加了对其他系统动画和 API 的支持,以创建自定义动画。有关更多信息,请参阅 添加对内置和自定义预测后退动画的支持

例如,使用后退手势可以在应用后面显示主屏幕的动画预览,如图 1 中的模型所示。从 Android 13 开始,您可以通过启用开发者选项(如本页所述)测试此后退到主屏幕动画

支持预测后退手势需要更新您的应用,使用向后兼容的 OnBackPressedCallback AppCompat 1.6.0-alpha05(AndroidX)或更高 API,或使用新的 OnBackInvokedCallback 平台 API。大多数应用将使用向后兼容的 AndroidX API。

此更新提供了一条迁移路径以正确拦截后退导航,这涉及到用新的系统后退 API 替换来自 KeyEvent.KEYCODE_BACK 和任何具有 onBackPressed 方法的类(如 ActivityDialog)的后退拦截。

Codelab 和 Google I/O 视频

除了在本页面查阅此文档外,还可以尝试我们的代码实验室。它提供了 WebView 使用 AndroidX Activity API 处理预测性后退手势的常见用例实现。

您还可以观看我们的 Google I/O 视频,其中涵盖了实现 AndroidX 和平台 API 的其他示例。

更新使用默认后退导航的应用

如果您的应用没有实现任何自定义后退行为(换句话说,它将后退处理留给系统),则更新您的应用以支持此功能非常简单。请按照本指南中的说明启用此功能

如果您的应用使用 Fragment 或 Navigation Component,请升级到AndroidX Activity 1.6.0-alpha05或更高版本。

更新使用自定义后退导航的应用

如果您的应用实现了自定义后退行为,则根据它是否使用 AndroidX 以及如何处理后退导航,会有不同的迁移路径。

您的应用使用 AndroidX 您的应用如何处理后退导航 推荐的迁移路径(此页面上的链接)
AndroidX API 迁移现有的 AndroidX 后退实现
不受支持的平台 API 将包含不受支持的后退导航 API 的 AndroidX 应用迁移到 AndroidX API
不受支持的平台 API,可以迁移 将使用不受支持的后退导航 API 的应用迁移到平台 API
不受支持的平台 API,但无法迁移 延迟启用,直到此功能成为必选功能。

迁移 AndroidX 后退导航实现

此用例最常见(也是最推荐的)。它适用于使用OnBackPressedDispatcher实现自定义手势导航处理的新应用或现有应用,如提供自定义后退导航中所述。

如果您的应用属于此类别,请按照以下步骤添加对预测性后退手势的支持

  1. 为了确保已经使用OnBackPressedDispatcher API(例如 Fragment 和 Navigation Component)的 API 与预测性后退手势无缝协作,请升级到AndroidX Activity 1.6.0-alpha05

    // In your build.gradle file:
    dependencies {
    
    // Add this in addition to your other dependencies
    implementation "androidx.activity:activity:1.6.0-alpha05"
    
  2. 启用预测性后退手势,如本页面所述。

将包含不受支持的后退导航 API 的 AndroidX 应用迁移到 AndroidX API

如果您的应用使用 AndroidX 库,但实现了或引用了不受支持的后退导航 API,则需要迁移到使用 AndroidX API 以支持新行为。

迁移不受支持的 API 到 AndroidX API

  1. 将您的系统后退处理逻辑迁移到 AndroidX 的OnBackPressedDispatcher,并实现OnBackPressedCallback。有关详细指南,请参阅提供自定义后退导航

  2. 准备好停止拦截后退手势时,禁用OnBackPressedCallback

  3. 停止通过OnBackPressedKeyEvent.KEYCODE_BACK拦截后退事件。

  4. 请确保升级到AndroidX Activity 1.6.0-alpha05

    // In your build.gradle file:
    dependencies {
    
    // Add this in addition to your other dependencies
    implementation "androidx.activity:activity:1.6.0-alpha05"
    
  5. 成功迁移应用后,启用预测性后退手势(如本页面所述),以查看返回主屏幕的系统动画。

将使用不受支持的后退导航 API 的应用迁移到平台 API

如果您的应用无法使用 AndroidX 库,而是使用不受支持的 API 实现或引用自定义后退导航,则必须迁移到OnBackInvokedCallback平台 API。

完成以下步骤将不受支持的 API 迁移到平台 API

  1. 在运行 Android 13 或更高版本的设备上使用新的OnBackInvokedCallback API,并在运行 Android 12 或更低版本的设备上依赖不受支持的 API。

  2. OnBackInvokedCallback中使用onBackInvokedDispatcher注册您的自定义后退逻辑。这可以防止当前活动结束,并且您的回调有机会在用户完成系统后退导航后对后退操作做出反应。

  3. 准备好停止拦截后退手势时,取消注册OnBackInvokedCallback。否则,用户在使用系统后退导航时可能会看到不良行为,例如在视图之间“卡住”并迫使他们强制退出您的应用。

    以下是如何将逻辑从onBackPressed中迁移出来的示例

    Kotlin

    @Override
    fun onCreate() {
        if (BuildCompat.isAtLeastT()) {
            onBackInvokedDispatcher.registerOnBackInvokedCallback(
                OnBackInvokedDispatcher.PRIORITY_DEFAULT
            ) {
                /**
                 * onBackPressed logic goes here. For instance:
                 * Prevents closing the app to go home screen when in the
                 * middle of entering data to a form
                 * or from accidentally leaving a fragment with a WebView in it
                 *
                 * Unregistering the callback to stop intercepting the back gesture:
                 * When the user transitions to the topmost screen (activity, fragment)
                 * in the BackStack, unregister the callback by using
                 * OnBackInvokeDispatcher.unregisterOnBackInvokedCallback
                 * (https://developer.android.com/reference/kotlin/android/window/OnBackInvokedDispatcher#unregisteronbackinvokedcallback)
                 */
            }
        }
    }
    

    Java

    @Override
    void onCreate() {
      if (BuildCompat.isAtLeastT()) {
        getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
            OnBackInvokedDispatcher.PRIORITY_DEFAULT,
            () -> {
              /**
               * onBackPressed logic goes here - For instance:
               * Prevents closing the app to go home screen when in the
               * middle of entering data to a form
               * or from accidentally leaving a fragment with a WebView in it
               *
               * Unregistering the callback to stop intercepting the back gesture:
               * When the user transitions to the topmost screen (activity, fragment)
               * in the BackStack, unregister the callback by using
               * OnBackInvokeDispatcher.unregisterOnBackInvokedCallback
               * (https://developer.android.com/reference/kotlin/android/view/OnBackInvokedDispatcher#unregisteronbackinvokedcallback)
               */
            }
        );
      }
    }
    
  4. 对于 Android 13 及更高版本,停止通过OnBackPressedKeyEvent.KEYCODE_BACK拦截后退事件。

  5. 成功迁移应用后,启用预测性后退手势(如本页面所述),以便OnBackInvokedCallback生效。

您可以使用PRIORITY_DEFAULTPRIORITY_OVERLAY注册OnBackInvokedCallback,这在类似的 AndroidX OnBackPressedCallback中不可用。在某些情况下,注册具有PRIORITY_OVERLAY的回调非常有用。一个适用此情况的示例是当您从onKeyPreIme()迁移并且您的回调需要接收后退手势而不是打开的 IME 时。IME 在打开时会使用PRIORITY_DEFAULT注册回调。使用PRIORITY_OVERLAY注册您的回调,以确保OnBackInvokedDispatcher将后退手势分派到您的回调而不是打开的 IME。

启用预测性后退手势

确定了如何根据您的情况更新应用后,请启用对预测性后退手势的支持。

要启用,请在AndroidManifest.xml<application>标签中,将android:enableOnBackInvokedCallback标志设置为true

<application
    ...
    android:enableOnBackInvokedCallback="true"
    ... >
...
</application>

如果您不提供值,则默认为false,并执行以下操作

  • 禁用预测性后退手势系统动画。
  • 忽略OnBackInvokedCallback,但OnBackPressedCallback调用继续工作。

在活动级别启用

从 Android 14 开始,android:enableOnBackInvokedCallback标志允许您在活动级别启用预测性系统动画。此行为使大型多活动应用更容易迁移到预测性后退手势。

以下代码显示了使用enableOnBackInvokedCallbackMainActivity启用返回主屏幕系统动画的示例

<manifest ...>
    <application . . .

        android:enableOnBackInvokedCallback="false">

        <activity
            android:name=".MainActivity"
            android:enableOnBackInvokedCallback="true"
            ...
        </activity>
        <activity
            android:name=".SecondActivity"
            android:enableOnBackInvokedCallback="false"
            ...
        </activity>
    </application>
</manifest>

在前面的示例中,为".SecondActivity"设置android:enableOnBackInvokedCallback=true将启用跨活动的系统动画。

使用android:enableOnBackInvokedCallback标志时,请记住以下注意事项

  • 设置android:enableOnBackInvokedCallback=false将在活动级别或应用级别关闭预测性后退动画(具体取决于您设置标签的位置),并指示系统忽略对OnBackInvokedCallback平台 API 的调用。但是,对OnBackPressedCallback的调用将继续运行,因为OnBackPressedCallback向后兼容并调用onBackPressed API,该 API 在 Android 13 之前不受支持。
  • 在应用级别设置enableOnBackInvokedCallback标志将为应用中的所有活动建立默认值。您可以通过在活动级别设置该标志来覆盖每个活动的默认值,如前面的代码示例所示。

回调最佳实践

以下是使用受支持的系统后退回调的最佳实践;BackHandler(用于 Compose)、OnBackPressedCallbackOnBackInvokedCallback

确定启用和禁用每个回调的 UI 状态

UI 状态是描述 UI 的属性。我们建议遵循以下高级步骤。

  1. 确定启用和禁用每个回调的 UI 状态。

  2. 使用可观察数据持有者类型(例如StateFlow或 Compose State)定义该状态,并在状态更改时启用或禁用回调。

如果您的应用以前将后退逻辑与条件语句相关联,这可能表示您在后退事件已发生后才对其做出反应,这是您应该避免使用较新回调的模式。如果可能,请将回调移到条件语句之外,而是将其与可观察数据持有者类型相关联。

将系统后退回调用于 UI 逻辑

UI 逻辑决定了如何显示 UI。使用系统后退回调运行 UI 逻辑,例如显示弹出窗口或运行动画。

如果您的应用启用了系统后退回调,则预测性动画不会运行,您必须处理后退事件。不要仅为了运行非 UI 逻辑而创建回调。

例如,如果您仅拦截后退事件以进行日志记录,请在 Activity 或 Fragment 生命周期内进行日志记录。

  • 对于活动到活动的情况或片段到活动的情况,如果 Activity 生命周期的onDestroy中的isFinishingtrue,则记录日志。
  • 对于片段到片段的情况,如果 Fragment 视图生命周期的onDestroy中的isRemoving为 true,则记录日志;或者,使用FragmentManager.OnBackStackChangedListener中的onBackStackChangeStartedonBackStackChangeCommitted方法记录日志。

对于 Compose 案例,请在与 Compose 目标关联的ViewModelonCleared()回调中记录日志。这是了解 Compose 目标何时从后退堆栈中弹出并销毁的最佳信号。

创建单一职责回调

这是可能的,因为您可以向调度程序添加多个回调。回调被添加到一个堆栈中,其中最后添加的已启用回调将处理下一个后退手势,每个后退手势一个回调。

测试预测性后退手势动画

从 Android 13 正式版开始,您应该能够启用一个开发者选项来测试图 1 中显示的返回主页动画。

要测试此动画,请完成以下步骤

  1. 在您的设备上,转到**设置 > 系统 > 开发者选项**。

  2. 选择**预测性返回动画**。

  3. 启动您更新后的应用,并使用返回手势查看其运行效果。