Jetpack Compose:拖动拖拽手柄关闭ModalBottomSheet时屏幕冻结
问题原因
你当前实现中,同时用showBottomSheet布尔状态和bottomSheetState控制底部弹窗的显示/隐藏,两者状态不同步是屏幕冻结的核心原因。拖拽关闭弹窗时,onDismissRequest直接将showBottomSheet设为false,弹窗组件被立即从Compose树移除,但bottomSheetState的关闭动画可能尚未完成,引发状态冲突导致UI冻结。
修复方案
- 统一状态管理:依赖
bottomSheetState状态控制弹窗显示,或确保两种状态严格同步。 - 规范关闭逻辑:拖拽关闭时通过协程触发
bottomSheetState.hide(),等待动画完成后再更新showBottomSheet;初始化bottomSheetState时设置skipPartiallyExpanded = true(无需部分展开状态时),避免状态歧义。
修改后的完整代码
CreateScaffold 函数
fun CreateScaffold() { // 初始化bottomSheetState,禁用部分展开状态避免状态冲突 val bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) val coroutineScope = rememberCoroutineScope() val showBottomSheet = remember { mutableStateOf(false) } Scaffold( bottomBar = { TestBottomAppBar() }, floatingActionButton = { ExtendedFloatingActionButton( onClick = { coroutineScope.launch { // 先更新布尔状态,再触发弹窗展开动画 showBottomSheet.value = true bottomSheetState.show() } } ) { Icon(imageVector = Icons.Default.Add, contentDescription = null, tint = Color.White) } } ) { paddingValues -> Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.SpaceAround, modifier = Modifier .fillMaxSize() .padding(paddingValues) ) { Button( onClick = { coroutineScope.launch { bottomSheetState.hide() }.invokeOnCompletion { if (!bottomSheetState.isVisible) { showBottomSheet.value = false } } } ) { Text(text = "Modal Bottom Sheet") } if (showBottomSheet.value) { ModalBottomSheet( // 拖拽关闭时先执行动画,完成后再更新布尔状态 onDismissRequest = { coroutineScope.launch { bottomSheetState.hide() }.invokeOnCompletion { if (!bottomSheetState.isVisible) { showBottomSheet.value = false } } }, sheetState = bottomSheetState, dragHandle = { BottomSheetDefaults.DragHandle( color = Color.DarkGray, height = 3.dp, width = 25.dp ) }, modifier = Modifier.height(350.dp) ) { Column(modifier = Modifier.padding(15.dp)) { LazyColumn { items(25) { Row( modifier = Modifier .fillMaxWidth() .padding(vertical = 8.dp), horizontalArrangement = Arrangement.SpaceAround, verticalAlignment = Alignment.CenterVertically ) { Icon( imageVector = Icons.Default.Share, contentDescription = null ) Text( text = "Share now", fontStyle = FontStyle.Italic ) } } } } } } } } }
关键修改点
- 初始化
rememberModalBottomSheetState时添加skipPartiallyExpanded = true,确保弹窗仅存在完全展开/隐藏两种状态,减少状态冲突可能。 - 点击FAB显示弹窗时,通过协程先更新
showBottomSheet状态,再触发bottomSheetState.show(),保证两种状态同步。 - 重写
onDismissRequest逻辑:不再直接设置showBottomSheet为false,而是等待bottomSheetState.hide()动画完成后再更新布尔状态,避免弹窗组件在动画中途被移除。
内容的提问来源于stack exchange,提问作者Himel Mazumder
相关产品推荐
相关产品推荐

