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

优化ModalBottomSheetLayout底部弹窗高度,解决切换时跳动问题

问题原因

你遇到的弹窗跳动问题,核心是依赖onGloballyPositioned动态获取TopAppBar高度的时机滞后:调用openSheet时,你立刻计算sumHeight并显示弹窗,但此时TopAppBar可能还没完成布局,topAppBarHeight还是初始的Dp.Unspecified,导致弹窗先以错误高度显示,等onGloballyPositioned触发后高度更新,就会出现跳动。

优化方案

方案1:提前固定TopAppBar高度,避免动态计算

Material组件的TopAppBar有明确的默认高度(比如标准SmallTopAppBar是56.dp),可以直接用常量代替动态获取,彻底消除计算滞后问题:

val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()

// 直接使用TopAppBar的标准高度,无需动态获取
val topAppBarHeight = 56.dp
var currentSheet by remember { mutableStateOf(0) }

val openSheet: (sheet: Int) -> Unit = {
    currentSheet = it
    scope.launch { sheetState.show() }
}
val closeSheet: () -> Unit = {
    scope.launch { sheetState.hide() }
}

ModalBottomSheetLayout(
    modifier = Modifier.fillMaxSize(),
    sheetState = sheetState,
    sheetContent = {
        Scaffold(
            // 移除手动设置的height,让内容自适应,ModalBottomSheet会自动计算高度
            topBar = {
                TopAppBar(
                    modifier = Modifier.clickable(onClick = closeSheet),
                    title = { Text("TopAppBarSheetContent") }
                )
            },
            content = { padding ->
                Box(
                    modifier = Modifier
                        .padding(padding) // 加上Scaffold的content padding
                        .height((currentSheet * 50).dp)
                        .fillMaxWidth()
                        .background(Color.Blue)
                )
            },
        )
    },
    content = {
        Scaffold(
            modifier = Modifier.fillMaxSize(),
            topBar = { TopAppBar(title = { Text("TopAppBarContent") }) },
            content = { innerPadding ->
                LazyColumn(
                    modifier = Modifier.padding(innerPadding),
                    contentPadding = PaddingValues(16.dp),
                    verticalArrangement = Arrangement.spacedBy(8.dp)
                ) {
                    items(50) { item ->
                        Box(
                            modifier = Modifier
                                .clip(CircleShape)
                                .fillMaxWidth()
                                .height(75.dp)
                                .background(Color.Red)
                                .clickable { openSheet(item) }
                        )
                    }
                }
            }
        )
    }
)

方案2:让内容自适应高度,完全放弃手动计算

如果TopAppBar高度可能动态变化(比如自定义样式),可以让sheetContent的内容自己决定高度,ModalBottomSheet会自动测量并使用正确的高度,无需手动计算总和:

val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
val scope = rememberCoroutineScope()

var currentSheet by remember { mutableStateOf(0) }

val openSheet: (sheet: Int) -> Unit = {
    currentSheet = it
    scope.launch { sheetState.show() }
}
val closeSheet: () -> Unit = {
    scope.launch { sheetState.hide() }
}

ModalBottomSheetLayout(
    modifier = Modifier.fillMaxSize(),
    sheetState = sheetState,
    sheetContent = {
        Scaffold(
            topBar = {
                TopAppBar(
                    modifier = Modifier.clickable(onClick = closeSheet),
                    title = { Text("TopAppBarSheetContent") }
                )
            },
            content = { padding ->
                Box(
                    modifier = Modifier
                        .padding(padding)
                        .height((currentSheet * 50).dp)
                        .fillMaxWidth()
                        .background(Color.Blue)
                )
            },
        )
    },
    content = {
        Scaffold(
            modifier = Modifier.fillMaxSize(),
            topBar = { TopAppBar(title = { Text("TopAppBarContent") }) },
            content = { innerPadding ->
                LazyColumn(
                    modifier = Modifier.padding(innerPadding),
                    contentPadding = PaddingValues(16.dp),
                    verticalArrangement = Arrangement.spacedBy(8.dp)
                ) {
                    items(50) { item ->
                        Box(
                            modifier = Modifier
                                .clip(CircleShape)
                                .fillMaxWidth()
                                .height(75.dp)
                                .background(Color.Red)
                                .clickable { openSheet(item) }
                        )
                    }
                }
            }
        )
    }
)
关键改进点
  • 移除了onGloballyPositioned动态获取高度的逻辑,避免布局回调滞后导致的高度计算错误
  • 去掉了手动设置sumHeight的代码,让ModalBottomSheet自动测量内容高度,从根源上解决跳动问题
  • 保留了原有的业务逻辑,只是优化了高度计算的方式

内容的提问来源于stack exchange,提问作者Sky

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 07:54:20