预测性返回是手势导航功能,可让用户预览返回滑动会带他们到哪里。
例如,使用返回手势可以显示应用背后主屏幕的动画预览,如图 1 所示。
从 Android 15 开始,预测性返回动画的开发者选项不再可用。回主屏幕、跨任务和跨 Activity 等系统动画现在会出现在已完全或在 Activity 级别选择启用预测性返回手势的应用中。
您可以测试此回主屏幕动画(如本页后续部分所述)。
支持预测性返回手势需要更新您的应用,使用向后兼容的 OnBackPressedCallback AppCompat 1.6.0-alpha05(AndroidX)或更高版本的 API,或者使用新的 OnBackInvokedCallback 平台 API。大多数应用使用向后兼容的 AndroidX API。
此更新提供了正确拦截返回导航的迁移路径,其中涉及将 KeyEvent.KEYCODE_BACK 和任何带有 onBackPressed 方法的类(例如 Activity 和 Dialog)的返回拦截替换为新的系统返回 API。
Codelab 和 Google I/O 视频
除了使用本页上的文档外,请尝试我们的 codelab。它提供了一个 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,但无法迁移 | 通过在您应用的 AndroidManifest.xml 文件的 <application> 或 <activity> 标签中将 android:enableOnBackInvokedCallback 属性设置为 false 来暂时退出。 |
迁移 AndroidX 返回导航实现
此用例最常见(也最推荐)。它适用于使用 OnBackPressedDispatcher 实现自定义手势导航处理的新应用或现有应用,如提供自定义返回导航所述。
为确保已在使用 OnBackPressedDispatcher 的 API(如 Fragment 和 Navigation Component)与预测性返回手势无缝协作,请升级到 AndroidX Activity 1.6.0-alpha05。
```xml
// In your build.gradle file:
dependencies {
// Add this in addition to your other dependencies
implementation "androidx.activity:activity:1.6.0-alpha05"
```
将包含不支持的返回导航 API 的 AndroidX 应用迁移到 AndroidX API
如果您的应用使用 AndroidX 库,但实现或引用了不支持的返回导航 API,您需要迁移到使用 AndroidX API 来支持新行为。
将不支持的 API 迁移到 AndroidX API
将您的系统返回处理逻辑迁移到 AndroidX 的
OnBackPressedDispatcher,并实现OnBackPressedCallback。有关详细指导,请参阅提供自定义返回导航。准备停止拦截返回手势时,禁用
OnBackPressedCallback。停止通过
OnBackPressed或KeyEvent.KEYCODE_BACK拦截返回事件。请务必升级到 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"
将使用不支持的返回导航 API 的应用迁移到平台 API
如果您的应用无法使用 AndroidX 库,而是使用不支持的 API 实现或引用自定义返回导航,则必须迁移到 OnBackInvokedCallback 平台 API。
完成以下步骤,将不支持的 API 迁移到平台 API
在运行 Android 13 或更高版本的设备上使用新的
OnBackInvokedCallbackAPI,并在运行 Android 12 或更低版本的设备上依赖不支持的 API。在
OnBackInvokedCallback中使用onBackInvokedDispatcher注册您的自定义返回逻辑。这会阻止当前 Activity 完成,并且一旦用户完成系统返回导航,您的回调就有机会对返回操作做出反应。准备停止拦截返回手势时,注销
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) */ } ); } }
对于 Android 13 及更高版本,停止使用
OnBackPressed或KeyEvent.KEYCODE_BACK拦截返回事件。
您可以注册一个具有 PRIORITY_DEFAULT 或 PRIORITY_OVERLAY 的 OnBackInvokedCallback,这在类似的 AndroidX OnBackPressedCallback 中不可用。在某些情况下,注册具有 PRIORITY_OVERLAY 的回调会很有帮助。
当您从 onKeyPreIme() 迁移并且您的回调需要接收返回手势而不是打开的 IME 时,这适用。IME 在打开时会注册具有 PRIORITY_DEFAULT 的回调。注册您的回调并设置 PRIORITY_OVERLAY,以确保 OnBackInvokedDispatcher 将返回手势分派给您的回调而不是打开的 IME。
退出预测性返回
要退出,请在 AndroidManifest.xml 中的 <application> 标签内,将 android:enableOnBackInvokedCallback 标志设置为 false。
<application
...
android:enableOnBackInvokedCallback="false"
... >
...
</application>
将其设置为 false 会执行以下操作:
- 禁用预测性返回手势系统动画。
- 忽略
OnBackInvokedCallback,但OnBackPressedCallback调用继续有效。
在 Activity 级别退出
从 Android 16 开始,android:enableOnBackInvokedCallback 标志允许您在 Activity 级别选择退出预测性系统动画。此行为使得将大型多 Activity 应用迁移到预测性返回手势更易于管理。
以下代码展示了将 enableOnBackInvokedCallback 设置为从 MainActivity 启用回主屏幕系统动画的示例
<manifest ...>
<application . . .
android:enableOnBackInvokedCallback="false">
<activity
android:name=".MainActivity"
android:enableOnBackInvokedCallback="true"
...
</activity>
<activity
android:name=".SecondActivity"
android:enableOnBackInvokedCallback="false"
...
</activity>
</application>
</manifest>
使用 android:enableOnBackInvokedCallback 标志时请记住以下注意事项:
- 将
android:enableOnBackInvokedCallback=false会在 Activity 级别或应用级别(取决于您设置标签的位置)关闭预测性返回动画,并指示系统忽略对OnBackInvokedCallback平台 API 的调用。但是,对OnBackPressedCallback的调用会继续运行,因为OnBackPressedCallback向后兼容并调用onBackPressedAPI,该 API 在 Android 13 之前不受支持。 - 在应用级别设置
enableOnBackInvokedCallback标志会为应用中的所有 Activity 建立默认值。您可以通过在 Activity 级别设置该标志来覆盖每个 Activity 的默认值,如前述代码示例所示。
回调最佳实践
以下是使用受支持的系统返回回调(BackHandler(适用于 Compose)、OnBackPressedCallback 或 OnBackInvokedCallback)的最佳实践。
确定启用和禁用每个回调的 UI 状态
UI 状态是描述 UI 的属性。我们建议遵循以下高级步骤。
确定启用和禁用每个回调的 UI 状态。
使用可观察数据持有者类型(例如
StateFlow或 Compose State)定义该状态,并随着状态更改启用或禁用回调。
如果您的应用之前将返回逻辑与条件语句相关联,这可能表示您在返回事件已发生后才对其做出反应。使用较新的回调避免这种模式。如果可能,将回调移到条件语句之外,并将其与可观察数据持有者类型相关联。
将系统返回回调用于 UI 逻辑
UI 逻辑决定如何显示 UI。使用系统返回回调运行 UI 逻辑,例如显示弹出窗口或运行动画。
如果您的应用启用系统返回回调,预测性动画将不会运行,您必须处理返回事件。不要仅为了运行非 UI 逻辑而创建回调。
例如,如果您仅为了日志记录而拦截返回事件,请改为在 Activity 或 Fragment 生命周期内进行日志记录。
- 对于 Activity-to-Activity 或 Fragment-to-Activity 的情况,如果 Activity 生命周期内
onDestroy中的isFinishing为true,则进行日志记录。 - 对于 Fragment-to-Fragment 的情况,如果 Fragment 视图生命周期内
onDestroy中的isRemoving为 true,则进行日志记录。或者使用FragmentManager.OnBackStackChangedListener中的onBackStackChangeStarted或onBackStackChangeCommitted方法进行日志记录。
对于 Compose 情况,在与 Compose 目标关联的 ViewModel 的 onCleared() 回调中进行日志记录。这是了解 Compose 目标何时从返回堆栈中弹出并销毁的最佳信号。
创建单一职责回调
您可以向分发器添加多个回调。回调被添加到堆栈中,其中最后一个添加的已启用回调处理下一个返回手势,每个返回手势一个回调。
如果回调具有单一职责,则更容易管理回调的启用状态。例如:
图 2 展示了您如何在堆栈中拥有多个回调,每个回调负责一件事。只有当堆栈中位于其上方的回调被禁用时,回调才会运行。在此示例中,当用户在表单中输入数据时,“您确定...”回调会启用,否则禁用。当用户向后滑动以退出表单时,该回调会打开一个确认对话框。
其他回调可以包括支持预测性返回的 Material 组件、使用 Progress API 的 AndroidX 转换或其他自定义回调。
如果上方回调被禁用且此 FragmentManager 的返回堆栈不为空(其中 childFragmentManager 附加在 Fragment 中),则 childFragmentManager 的回调会运行。在此示例中,此内部回调被禁用。
同样,如果上方回调被禁用且其堆栈不为空,则 supportFragmentManager 的内部回调会运行。当使用 FragmentManager 或 NavigationComponent 进行导航时,此行为是一致的,因为 NavigationComponent 依赖于 FragmentManager。在此示例中,如果用户未在表单中输入文本,导致“您确定...”回调被禁用,则此回调会运行。
最后,super.onBackPressed() 是系统级回调,如果上方回调被禁用,它也会运行。为了触发系统动画(例如回主屏幕、跨 Activity 和跨任务),supportFragmentManager 的返回堆栈必须为空,以便其内部回调被禁用。
测试预测性返回手势动画
如果您仍在使用 Android 13 或 Android 14,可以测试图 1 中所示的回主屏幕动画。
要测试此动画,请完成以下步骤:
在您的设备上,前往设置 > 系统 > 开发者选项。
选择预测性返回动画。
启动您更新后的应用,并使用返回手势查看其效果。