提供自定义返回导航

用户使用 返回导航在界面之间向后导航。大多数 Android 设备都有一个返回按钮(实体、软件或基于手势)。通常,您不应向应用添加返回按钮。不过,兼容模式下的 Android Automotive OS (AAOS) 设备使用系统返回按钮。此按钮可处理导航,因此您无需添加自己的返回按钮。如需了解详情,请参阅 AAOS 兼容模式。

用户在您的应用中导航时,Android 会维护目的地的 返回堆栈。这样,当用户按返回按钮时,Android 通常可以正确地导航到之前的目的地。不过,在少数情况下,您的应用可能需要实现自己的“返回”行为,以便提供最佳用户体验。例如,使用 WebView 时,您可能需要替换默认返回按钮行为,以允许用户通过其网页浏览记录(而非应用中之前访问过的屏幕)返回。

在 Compose 中实现自定义返回导航

在 Jetpack Compose 中,您可以使用 BackHandler 可组合项处理自定义返回导航。

使用 Navigation Compose 时,您通常使用 NavController.navigateUp() 或 NavController.popBackStack() 导航到返回堆栈中的上一个界面。不过,当您希望在用户按系统返回按钮或使用返回手势时实现自定义行为时,BackHandler 非常有用。例如,如果您 在应用中显示 WebView,您可能希望允许用户 在按系统返回按钮时通过浏览记录返回。

基本用法

以下示例展示了如何拦截返回事件以控制自定义状态(例如收起面板):

@Composable
fun MyScreen() {
    var isExpanded by remember { mutableStateOf(false) }

    // Intercept the back button or gesture only when isExpanded is true
    BackHandler(enabled = isExpanded) {
        // Collapsing the content disables this handler, so it does not
        // receive the next back event.
        isExpanded = false
    }

    if (isExpanded) {
        Text("Expanded content. Go back to collapse it.")
    } else {
        Button(onClick = { isExpanded = true }) {
            Text("Expand")
        }
    }
}

可组合项树拦截

如果您在可组合项树的不同级别有多个已启用的 BackHandler 可组合项,则只有最内层的可组合项会拦截返回事件。

使用 View 实现自定义返回导航

ComponentActivity(FragmentActivity 和 AppCompatActivity 的基类)允许您使用其 OnBackPressedDispatcher 控制返回按钮的行为,您可以通过调用 getOnBackPressedDispatcher() 检索该行为。

OnBackPressedDispatcher 控制如何将返回按钮事件分派 给一个或多个 OnBackPressedCallback 对象。OnBackPressedCallback 的构造函数接受一个布尔值作为初始启用状态。只有在 启用回调时(例如 isEnabled() 返回 true 时),调度程序才会调用回调的 handleOnBackPressed() 来处理 返回按钮事件。您可以通过调用 setEnabled() 更改启用状态。

使用 addCallback 方法添加回调。使用 addCallback()方法,该方法接受LifecycleOwner。这样,只有当LifecycleOwner 为 Lifecycle.State.STARTED 时,才会添加 OnBackPressedCallback。此外,与注册的回调相关联的 LifecycleOwner 被销毁时,相应 activity 还会移除注册的回调。这不仅可以防止内存泄漏,还可以使其适用于生命周期短于该 activity 的 fragment 或其他生命周期所有者。

以下是一个回调实现示例:

class MyFragment : Fragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // This callback will only be called when MyFragment is at least Started.
        val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
            // Handle the back button event
        }

        // The callback can be enabled or disabled here or in the lambda
    }
    ...
}

您可以使用 addCallback() 提供多个回调。 这样做时,系统会按添加回调的相反顺序调用回调,即最后添加的回调是第一个有机会处理返回按钮事件的回调。例如,如果您按顺序添加了三个名为 one、two 和 three 的回调,则系统会按 three、two 和 one 的顺序调用它们。

回调遵循 责任链 模式。只有在前面的回调未启用时,才会调用链中的每个回调。这意味着,在前面的示例中,只有在回调 three 未启用时,才会调用回调 two。只有在回调 two 未启用时,才会调用回调 one,并且此模式适用于任何其他回调。

请注意,使用 addCallback() 添加时,只有当 LifecycleOwner 进入 Lifecycle.State.STARTED 状态时,才会将回调添加到责任链。

强烈建议您更改回调的启用状态以进行临时更改,因为它会保持前面所述的顺序,如果您在多个不同的嵌套生命周期所有者上注册了回调,这一点尤其重要。

如果您想完全移除回调,请调用 remove()。 通常没有必要这样做,因为当与回调关联的 LifecycleOwner 被 销毁时,系统会自动 移除回调。