Jetpack Compose中ModalBottomSheet如何向上一页面回传值
Jetpack Compose ModalBottomSheet 收起并回传数据实现方案
核心逻辑靠Compose的状态提升机制实现,不要在弹窗内部私藏状态,把弹窗显示控制、数据接收的状态都放在弹窗的父页面(也就是唤起弹窗的上一级页面)持有即可。
具体实现步骤
- 父页面统一管理核心实例:协程作用域(用来调用挂起的弹窗收起方法)、底部弹窗状态对象、弹窗显示标记位、回传数据的接收状态
- 弹窗内部按钮点击时按顺序执行逻辑:先挂起等待弹窗完全收起动画执行完成,再把待传递的数据赋值给父页面的状态,最后更新弹窗显示标记位移除弹窗组合
- 禁止提前把弹窗显示标记位置为false,否则弹窗会被直接从视图树移除,既会打断收起动画,还会触发
ModalBottomSheet的状态访问异常
完整可运行代码示例
@OptIn(ExperimentalMaterial3Api::class) @Composable fun UpperLevelPage() { // 父页面持有的所有状态,不放在弹窗内部 val coroutineScope = rememberCoroutineScope() val bottomSheetState = rememberModalBottomSheetState() var showBottomSheet by remember { mutableStateOf(false) } // 替换成你自己的业务数据类型即可,自定义数据类、基本类型都支持 var backDataFromSheet by remember { mutableStateOf("初始无数据") } Scaffold { innerPadding -> Column( modifier = Modifier .fillMaxSize() .padding(innerPadding), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally ) { Text(text = "接收到的弹窗回传内容:$backDataFromSheet") Spacer(modifier = Modifier.height(20.dp)) Button(onClick = { showBottomSheet = true }) { Text(text = "唤起底部弹窗") } } // 控制弹窗渲染 if (showBottomSheet) { ModalBottomSheet( onDismissRequest = { showBottomSheet = false }, sheetState = bottomSheetState ) { Column( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 24.dp), horizontalAlignment = Alignment.CenterHorizontally ) { // 你要回传的业务数据 val targetData = "弹窗操作生成的业务数据" Button(onClick = { coroutineScope.launch { // 第一步:等待弹窗收起动画完全执行完成 bottomSheetState.hide() // 第二步:给父页面状态赋值,完成数据传递 backDataFromSheet = targetData // 第三步:标记弹窗隐藏,从组合中移除弹窗 showBottomSheet = false } }) { Text(text = "收起弹窗并回传数据") } } } } } }
复杂场景适配
如果页面层级较深,不想逐层传递回调,可以把状态抽成共享ViewModel:父页面和弹窗从同一个导航栈条目获取ViewModel实例,弹窗内部直接修改ViewModel中暴露的可观察状态,父页面对该状态做观察即可,本质还是状态上提的思路,只是状态存放位置移到了ViewModel。
注意:不要尝试用路由框架的返回栈传参、或者全局EventBus实现这个逻辑,会破坏生命周期一致性,极易产生内存泄漏和状态不一致问题。
内容的提问来源于stack exchange,提问作者Saeed Noshadi
相关产品推荐
相关产品推荐

