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

如何为BottomSheet设置与PartiallyExpanded等高的最小高度?

Material3 ModalBottomSheet 半展开状态高度计算逻辑及应用

需求说明

我自定义了一个BottomSheet组件(代码如下),通过rememberModalBottomSheetState管理其状态,现在需要明确**PartiallyExpanded(半展开)**状态的高度计算逻辑,从而给这个自定义BottomSheet设置与该高度一致的最小高度。

自定义BottomSheet实现代码

@Composable
@OptIn(ExperimentalMaterial3Api::class)
fun BottomSheet(
    modifier: Modifier = Modifier,
    isBottomSheetVisible: Boolean,
    sheetState: SheetState,
    shape: Shape = RoundedCornerShape(topStart = 12.dp, topEnd = 12.dp),
    onDismiss: () -> Unit,
    content: @Composable ColumnScope.() -> Unit
) {
    if (isBottomSheetVisible) {
        ModalBottomSheet(
            modifier = modifier,
            onDismissRequest = onDismiss,
            sheetState = sheetState,
            tonalElevation = 0.dp,
            shape = shape,
            dragHandle = null,
            windowInsets = WindowInsets(0, 0, 0, 0)
        ) {
            Column(
                modifier = Modifier
                    .fillMaxWidth()
                    .padding(start = 16.dp, end = 16.dp, bottom = 30.dp)
                    .navigationBarsPadding()
                    .animateContentSize()
            ) {
                Spacer(modifier = Modifier.height(10.dp))
                Box(
                    modifier = Modifier
                        .size(height = 4.dp, width = 32.dp)
                        .clip(RoundedCornerShape(100.dp))
                        .background(almaColorPalette.neutral4)
                        .align(alignment = Alignment.CenterHorizontally)
                )
                Spacer(modifier = Modifier.height(15.dp))
                content()
            }
        }
    }
}

状态初始化代码

val sheetState = rememberModalBottomSheetState()

半展开状态高度的源码计算逻辑

Material3中ModalBottomSheet的半展开高度计算逻辑封装在核心源码里,核心规则如下:

  • 基础比例:默认取屏幕可用高度的50%,这里的可用高度是指屏幕总高度减去系统窗口Insets(状态栏、导航栏等系统占据的高度)。
  • 源码核心逻辑:
    在calculatePartiallyExpandedHeight方法中,核心计算逻辑简化后如下:
    private fun calculatePartiallyExpandedHeight(
        windowSizeClass: WindowSizeClass,
        windowInsets: WindowInsets
    ): Dp {
        val usableHeight = windowSizeClass.windowHeightDp - 
                          windowInsets.getTop(LocalDensity.current) - 
                          windowInsets.getBottom(LocalDensity.current)
        return usableHeight * 0.5f
    }
    
    注:大屏设备(如平板)会根据窗口尺寸类调整比例,但手机端默认是50%可用高度。
  • 额外约束:计算出的半展开高度不会小于底部导航栏高度,同时如果内容自身高度小于该计算值,会以内容实际高度为准。

给自定义BottomSheet设置对应最小高度

要让自定义BottomSheet的最小高度匹配系统半展开高度,可按以下步骤实现:

  1. 获取窗口相关参数
    在Composable中获取窗口尺寸类和系统Insets:

    val windowSizeClass = calculateWindowSizeClass(LocalContext.current)
    val windowInsets = WindowInsets.systemBars
    val density = LocalDensity.current
    
  2. 计算半展开高度
    按照源码逻辑计算目标高度:

    val partiallyExpandedHeight = with(density) {
        val usableHeight = windowSizeClass.windowHeightDp.dp - 
                          windowInsets.getTop(this) - 
                          windowInsets.getBottom(this)
        usableHeight * 0.5f
    }
    
  3. 应用最小高度到组件
    修改自定义BottomSheet中的Column修饰符,添加minimumHeight约束:

    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(start = 16.dp, end = 16.dp, bottom = 30.dp)
            .navigationBarsPadding()
            .animateContentSize()
            .minimumHeight(partiallyExpandedHeight) // 添加最小高度约束
    ) {
        // 原有内容保持不变
    }
    

这样就能确保自定义BottomSheet的最小高度与系统默认的半展开高度完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 08:32:17