在 Jetpack Compose 中实现 Android 15 的预测性返回

社区移动开发Android

picture.image

在 Jetpack Compose 中实现 Android 中的预测性返回

在 Android 15 中引入的预测性返回功能通过为返回导航提供系统管理的动画来增强用户体验. 当用户在应用和系统中导航时,这将创建一个视觉上更一致, 更直观的流程.

**让我们来学习如何在你的 Android 应用, Jetpack Compose 和传统视图中实现预测性返回功能.

主要内容

  • Android 15中的预测性返回
  • 配置证明文件
  • 使用Jetpack Compose的方式

🎯 管理配置

如果你的应用不拦截返回事件,只需在AndroidManifest.xml中的application标记中添加android:enableOnBackInvokedCallback=“true”,即可启用预测性返回:

picture.image

🎯 如何处理返回导航

对于需要拦截返回事件(例如,Confirm丢弃更改)的应用,你需要使用 OnBackInvokedCallback API 并以编程方式处理返回导航.

🎯 在 Compose 中,使用 BackHandler Composable拦截返回事件. 在 onBack lambda 中,你可以执行自定义操作,并有条件地调用 onBackInvokedDispatcher.onBackPressed() 来触发系统的返回导航.

picture.image

picture.image

picture.image

🎯 实现:

本代码定义了一组Composable项,用于处理 Android 应用中的预测性返回导航:

@Composable
fun MyFirstPredictiveBackScreen() {
    var showDialog by remember { mutableStateOf(false) }
    // Use only if it is not first screen of activity.
    val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher

    val activity = LocalContext.current as Activity // Get the current activity

    BackPressHandler(showDialog) {
        showDialog = true
    }

    if (showDialog) {
        ConfirmExitDialog(
            onConfirm = {
                showDialog = false
                /**
                 * In the case of the first screen in an activity,
                 * simply calling onBackPressedDispatcher?.onBackPressed()
                 * would indeed cause the dialog to show again,
                 * leading to an infinite loop.
                 * onBackPressedDispatcher?.onBackPressed()
                */
                activity.finish() // Finish the activity to exit the app if is the first screen
            },
            onDismiss = { showDialog = false }
        )
    }

    Column (
        modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars)
    ){
        Text(text = "My First Screen Content")
    }

}

MyFirstPredictiveBackScreen

此Composable元素专为活动的第一个屏幕而设计.

  • showDialog: 一个可变状态变量,用于控制Confirm对话框的可见性.
  • onBackPressedDispatcher**: 注释掉了,因为第一个屏幕不需要它. 在这里调用 onBackPressed()会导致循环,因为它会再次触发后按处理程序.
  • 活动: 使用LocalContext获取当前活动.
  • BackPressHandler: 一个Composable,用于拦截返回按键并将 showDialog 设置为 true.
  • ConfirmExitDialog: 一个Composable,用于显示Confirm对话框. 如果用户Confirm,将调用 activity.finish() 关闭活动并退出应用.
@Composable
fun MyPredictiveBackScreen() {
    var showDialog by remember { mutableStateOf(false) }
    val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher

    BackPressHandler(showDialog) {
        showDialog = true
    }

    if (showDialog) {
        ConfirmExitDialog(
            onConfirm = {
                showDialog = false
                onBackPressedDispatcher?.onBackPressed() // the screen is not first screen so call the system back
            },
            onDismiss = { showDialog = false }
        )
    }

    Column (
        modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars)
    ){
        Text(text = "My Screen Content")
    }
}

MyPredictiveBackScreen

该Composable适用于活动中除第一个屏幕之外的其他屏幕.

  • onBackPressedDispatcher: 获取 OnBackPressedDispatcher 以处理反向按压.
  • 调用onBackPressedDispatcher.onBackPressed() 可触发系统的返回导航.
@Composable
fun BackPressHandler(showDialog: Boolean, onBack: () -> Unit) {
    val onBackPressedDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
    val lifecycleOwner = androidx.lifecycle.compose.LocalLifecycleOwner.current

    DisposableEffect(lifecycleOwner, onBackPressedDispatcher) {
        val callback = object : androidx.activity.OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                if (!showDialog) {
                    onBack()
                }
            }
        }
        onBackPressedDispatcher?.addCallback(lifecycleOwner, callback)

        onDispose {
            callback.remove()
        }
    }
}

BackPressHandler

此Composable程序可拦截返回按键.

  • showDialog: 指示当前是否显示对话框.
  • onBack: 当按下返回按钮时执行的 lambda 函数(如果对话框未显示).
  • onBackPressedDispatcher: 获取OnBackPressedDispatcher.
  • lifecycleOwner: 获取当前生命周期所有者.
  • DisposableEffect: 注册一个OnBackPressedCallback,用于拦截回按. 如果 showDialog 为 false,它会调用 onBack lambda. 该回调会在Composable元素被弃置时移除.
@Composable
fun ConfirmExitDialog(onConfirm: () -> Unit, onDismiss: () -> Unit) {
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("Confirm Exit") },
        text = { Text("Are you sure you want to exit?") },
        confirmButton = {
            Button(onClick = onConfirm) {
                Text("Yes")
            }
        },
        dismissButton = {
            Button(onClick = onDismiss) {
                Text("No")
            }
        }
    )
}

ConfirmExitDialog

此Composable元素会显示一个Confirm对话框.

  • onConfirm: 当用户Confirm时执行的 lambda 函数.
  • onDismiss: 当用户Confirm时执行的 lambda 函数: 当用户取消对话框时执行的 lambda 函数.
  • AlertDialog: Material Design AlertDialog,包含标题, 文本和Confirm/Cancel按钮.

好了, 今天的内容就分享到这里啦!

一家之言, 欢迎拍砖!

Happy Coding! Stay GOLDEN!

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论