You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose:拖动拖拽手柄关闭ModalBottomSheet时屏幕冻结

问题原因

你当前实现中,同时用showBottomSheet布尔状态和bottomSheetState控制底部弹窗的显示/隐藏,两者状态不同步是屏幕冻结的核心原因。拖拽关闭弹窗时,onDismissRequest直接将showBottomSheet设为false,弹窗组件被立即从Compose树移除,但bottomSheetState的关闭动画可能尚未完成,引发状态冲突导致UI冻结。

修复方案
  1. 统一状态管理:依赖bottomSheetState状态控制弹窗显示,或确保两种状态严格同步。
  2. 规范关闭逻辑:拖拽关闭时通过协程触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 01:04:52