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

Jetpack Compose Material3 BottomSheetScaffold适配内容高度而非全屏展开问题

解决BottomSheetScaffold展开至内容实际高度的方案

要让BottomSheetScaffold展开后适配内容实际高度而非全屏,核心思路是动态测量sheet内容的高度,并将其作为底部弹窗的最大高度限制。以下是具体实现步骤:

1. 核心实现代码

首先在父Composable中添加状态保存内容高度,同时修改sheetContent的布局测量逻辑:

父组件代码

@Composable
fun YourBottomSheetScreen() {
    val cornerRadius = 16.dp
    val isSheetSwipeEnabled = true
    // 保存sheet内容的实际高度
    val sheetContentHeight = remember { mutableStateOf(0.dp) }
    val bottomSheetState = rememberBottomSheetState(
        initialValue = BottomSheetValue.Collapsed,
        skipHiddenState = true
    )
    val coroutineScope = rememberCoroutineScope()

    BottomSheetScaffold(
        modifier = Modifier.fillMaxHeight(),
        sheetContent = {
            GetSheetContent { measuredHeight ->
                sheetContentHeight.value = measuredHeight
            }
        },
        sheetDragHandle = {
            // 添加默认拖拽手柄(可选,提升交互体验)
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(vertical = 8.dp)
                    .height(4.dp)
                    .background(Color.Gray, RoundedCornerShape(2.dp))
            )
        },
        sheetShape = RoundedCornerShape(topStart = cornerRadius, topEnd = cornerRadius),
        sheetPeekHeight = 100.dp, // 初始折叠状态高度,可按需调整
        // 展开时最大高度限制为内容实际高度,初始值设为最小高度避免异常
        sheetMaxHeight = max(sheetContentHeight.value, 200.dp),
        sheetSwipeEnabled = isSheetSwipeEnabled,
        sheetState = bottomSheetState
    ) {
        // 主内容区域,示例添加触发按钮
        Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
            Button(
                onClick = {
                    coroutineScope.launch {
                        if (bottomSheetState.isCollapsed) bottomSheetState.expand()
                        else bottomSheetState.collapse()
                    }
                }
            ) {
                Text("切换底部弹窗")
            }
        }
    }
}

修改后的sheetContent代码

@Composable
fun GetSheetContent(onHeightChanged: (Dp) -> Unit) {
    Column(
        modifier = Modifier
            .fillMaxWidth() // 必须设置,确保宽度正确,高度测量准确
            .onSizeChanged { size ->
                // 将像素高度转为Dp并回调给父组件
                with(LocalDensity.current) {
                    onHeightChanged(size.height.toDp())
                }
            }
            .verticalScroll(rememberScrollState()) // 内容过长时允许滚动
            .padding(16.dp) // 添加内边距优化显示
    ) {
        Image(
            painter = painterResource(id = R.drawable.ic_location),
            contentDescription = "位置图标",
            modifier = Modifier.size(48.dp) // 固定图片大小,避免高度不确定
        )
        Text(
            modifier = Modifier
                .semantics { heading() }
                .padding(top = 16.dp, bottom = 8.dp),
            text = stringResource(id = titleId),
            style = MaterialTheme.typography.headlineSmall
        )
        Text(
            text = stringResource(id = description),
            style = MaterialTheme.typography.bodyMedium
        )
    }
}

2. 关键细节说明

  • 高度测量:通过Modifier.onSizeChanged监听内容布局完成后的实际尺寸,转换为Dp后保存到状态中。
  • 最大高度限制:将sheetMaxHeight设置为测量到的内容高度,确保弹窗展开时不会超出内容实际高度;同时设置最小高度(如200.dp)避免初始状态下弹窗高度为0。
  • 滚动处理:给Column添加verticalScroll,当内容高度超过屏幕时,允许用户滚动查看全部内容。
  • 布局稳定性:给图片设置固定大小、添加内边距,避免因自适应元素导致高度测量异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 19:03:14