Android Compose 显示底部对话框 (ModalBottomSheet),实现类似BottomSheetDialog的效果

1. ModalBottomSheet

ModalBottomSheetCompose官方的底部对话框,类似传统View中的BottomSheetDialog,可以实现从底部弹出,并支持滑动关闭的效果。

需要注意的是,这里使用的是material3,然后ModalBottomSheet这个组件目前还是实验性的,未来可能会改变或删除。

kotlin 复制代码
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyModalBottomSheetTest1() {
    val sheetState = rememberModalBottomSheetState()
    val scope = rememberCoroutineScope()
    var showBottomSheet by remember { mutableStateOf(false) }

    if (showBottomSheet) {
        ModalBottomSheet(
            onDismissRequest = {
                showBottomSheet = false
            },
            sheetState = sheetState
        ) {
            // Sheet content
            Column(Modifier.height(300.dp)) {
                Button(onClick = {
                    scope.launch { sheetState.hide() }.invokeOnCompletion {
                        if (!sheetState.isVisible) {
                            showBottomSheet = false
                        }
                    }
                }) {
                    Text("Hide bottom sheet")
                }
            }
        }
    }

    Button(onClick = {
        showBottomSheet = true
    }, Modifier.padding(50.dp)) {
        Text("show")
    }
}

效果如下

2. 自定义圆角大小

通过定义ModalBottomSheetshape可以修改圆角的大小

kotlin 复制代码
shape = RoundedCornerShape(topStart = 3.dp, topEnd = 3.dp)

完整代码如下

kotlin 复制代码
//修改圆角
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyModalBottomSheetTest2() {
    val sheetState = rememberModalBottomSheetState()
    val scope = rememberCoroutineScope()
    var showBottomSheet by remember { mutableStateOf(false) }

    if (showBottomSheet) {
        ModalBottomSheet(
            shape = RoundedCornerShape(topStart = 3.dp, topEnd = 3.dp),
            onDismissRequest = {
                showBottomSheet = false
            },
            sheetState = sheetState
        ) {
            // Sheet content
            Column(Modifier.height(300.dp)) {
                Button(onClick = {
                    scope.launch { sheetState.hide() }.invokeOnCompletion {
                        if (!sheetState.isVisible) {
                            showBottomSheet = false
                        }
                    }
                }) {
                    Text("Hide bottom sheet")
                }
            }
        }
    }

    Button(onClick = {
        showBottomSheet = true
    }, Modifier.padding(50.dp)) {
        Text("show")
    }
}

效果如下

3. 去除拖动条

对话框顶部的拖动条,我们可能不需要,可以将其去除。

通过定义ModalBottomSheetdragHandle可以去除拖动条。

kotlin 复制代码
dragHandle = {}

完整代码如下

kotlin 复制代码
//去除拖动条
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyModalBottomSheetTest3() {
    val sheetState = rememberModalBottomSheetState()
    val scope = rememberCoroutineScope()
    var showBottomSheet by remember { mutableStateOf(false) }

    if (showBottomSheet) {
        ModalBottomSheet(
            dragHandle = {},
            onDismissRequest = {
                showBottomSheet = false
            },
            sheetState = sheetState
        ) {
            // Sheet content
            Column(Modifier.height(300.dp)) {
                Button(onClick = {
                    scope.launch { sheetState.hide() }.invokeOnCompletion {
                        if (!sheetState.isVisible) {
                            showBottomSheet = false
                        }
                    }
                }) {
                    Text("Hide bottom sheet")
                }
            }
        }
    }

    Button(onClick = {
        showBottomSheet = true
    }, Modifier.padding(50.dp)) {
        Text("show")
    }
}

效果如下

4. 默认半屏,滑动变成全屏

这里我们把Column的高度改为800.dp,运行程序,对话框默认以半屏显示,向上滑动对话框,可以发现,对话框会变为全屏。

kotlin 复制代码
//半屏展开
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyModalBottomSheetTest4() {
    val sheetState = rememberModalBottomSheetState(
        skipPartiallyExpanded = false,
    )
    val scope = rememberCoroutineScope()
    var showBottomSheet by remember { mutableStateOf(false) }

    if (showBottomSheet) {
        ModalBottomSheet(
            onDismissRequest = {
                showBottomSheet = false
            },
            sheetState = sheetState
        ) {
            // Sheet content
            Column(Modifier.height(800.dp)) {
                Button(onClick = {
                    scope.launch { sheetState.hide() }.invokeOnCompletion {
                        if (!sheetState.isVisible) {
                            showBottomSheet = false
                        }
                    }
                }) {
                    Text("Hide bottom sheet")
                }
            }
        }
    }

    Button(onClick = {
        showBottomSheet = true
    }, Modifier.padding(50.dp)) {
        Text("show")
    }
}

效果如下所示

5. 默认全屏

skipPartiallyExpanded修改为true,打开对话框的时候,会立即以全屏展示,向下滑动回收的时候,也会跳过半屏阶段。

kotlin 复制代码
//全屏展开
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyModalBottomSheetTest5() {
    val sheetState = rememberModalBottomSheetState(
        skipPartiallyExpanded = true,
    )
    val scope = rememberCoroutineScope()
    var showBottomSheet by remember { mutableStateOf(false) }

    if (showBottomSheet) {
        ModalBottomSheet(
            onDismissRequest = {
                showBottomSheet = false
            },
            sheetState = sheetState
        ) {
            // Sheet content
            Column(Modifier.height(800.dp)) {
                Button(onClick = {
                    scope.launch { sheetState.hide() }.invokeOnCompletion {
                        if (!sheetState.isVisible) {
                            showBottomSheet = false
                        }
                    }
                }) {
                    Text("Hide bottom sheet")
                }
            }
        }
    }

    Button(onClick = {
        showBottomSheet = true
    }, Modifier.padding(50.dp)) {
        Text("show")
    }
}

效果如下所示

6. 返回键不隐藏弹框

将properties中的shouldDismissOnBackPress设置为false,返回键将不会关闭弹框。

kotlin 复制代码
properties = ModalBottomSheetProperties(shouldDismissOnBackPress = false)

7. 修改对话框的主体颜色

containerColor可以修改对话框的主体颜色,如果弹出的弹框底部横条颜色和对话框背景颜色不一样,可以通过修改containerColor来达到颜色一直的效果。

8. 更多ModalBottomSheet的使用

更多ModalBottomSheet的使用详见 : Android Developers | 底部动作条

9.其他三方的Compose底部对话框库

9.1 bottomsheetdialog-compose

Github地址 : workspace/bottomsheetdialog-compose

Jetpack Compose BottomSheetDialog 库,允许您像使用 Dialog 的界面一样使用BottomsheetDialog。此外,它还支持在 BottomSheetDialog 显示时设置导航栏颜色。

这个看一下它的源码,可以发现内部调用的BottomSheetDialogWrapper,而BottomSheetDialogWrapper继承自com.google.android.material.bottomsheet.BottomSheetDialog,也就是说,bottomsheetdialog-compose这个库实质上是封装了传统View中的BottomSheetDialog,来提供给Compose使用。

kotlin 复制代码
private class BottomSheetDialogWrapper(
    private var onDismissRequest: () -> Unit,
    private var properties: BottomSheetDialogProperties,
    private val composeView: View,
    layoutDirection: LayoutDirection,
    density: Density,
    dialogId: UUID
) : BottomSheetDialog(
    ContextThemeWrapper(
        composeView.context,
        if (properties.enableEdgeToEdge) {
            R.style.TransparentEdgeToEdgeEnabledBottomSheetTheme
        } else {
            R.style.TransparentEdgeToEdgeDisabledBottomSheetTheme
        }
    )
)
9.2 FlexibleBottomSheet

Github地址 : skydoves/FlexibleBottomSheet

FlexibleBottomSheet 是一种高级的 Compose Multiplatform 底部工作表,用于分段大小调整、非模态类型,并允许在底部工作表后面进行交互,类似于 Google Maps。它还提供了其他便利,包括指定工作表大小、监视工作表状态和更多自定义。

相关推荐
邪修king1 小时前
UE5 零基础入门第四弹:UMG UI 系统入门,从静态界面到逻辑联动
c++·ui·ue5
薛定猫AI2 小时前
【深度解析】Open Design:用本地优先架构重塑 AI UI 生成工作流
人工智能·ui·架构
Gary Studio8 小时前
安卓HAL编写
android
_李小白11 小时前
【android opencv学习笔记】Day 2: Mat类(图片数据结构体)
android·opencv·学习
jinanwuhuaguo12 小时前
OpenClaw工程解剖——RAG、向量织构与“记忆宫殿”的索引拓扑学(第十三篇)
android·开发语言·人工智能·kotlin·拓扑学·openclaw
小怪吴吴14 小时前
idea 开发Android
android·java·intellij-idea
xiaoyan201515 小时前
2026爆肝!Flutter3.41纯手撸微信聊天APP原生应用
android·flutter·dart
魔士于安15 小时前
Unity UI图片 复活节UI,卡通风格
游戏·ui·unity·游戏引擎·材质·贴图
jinanwuhuaguo16 小时前
OpenClaw协议霸权——从 MCP 标准到意图封建化的政治经济学(第十八篇)
android·人工智能·kotlin·拓扑学·openclaw
for_ever_love__16 小时前
UI学习:UITableView的基本操作及折叠cell
学习·ui·ios