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。它还提供了其他便利,包括指定工作表大小、监视工作表状态和更多自定义。

相关推荐
chian-ocean10 分钟前
进程的家园:探索 Linux 地址空间的奥秘
android·java·linux
c1assy31 分钟前
天机学堂3-ES+Caffeine
android·java·elasticsearch
Dnelic-8 小时前
Kotlin | Android Provider 的实现案例
android·数据库·kotlin·provider·自学笔记
walkskyer11 小时前
Golang strconv包详解:高效类型转换实战
android·开发语言·golang
我命由我1234511 小时前
Android Room 构建问题:There are multiple good constructors
android·开发语言·java-ee·android studio·android jetpack·android-studio·android runtime
c小旭11 小时前
Android SystemUI——服务启动流程(二)
android·systemui
zhangphil13 小时前
Android ValueAnimator根据屏幕刷率动态出帧/刷新,Kotlin
android·kotlin
芝士就是力量啊 ೄ೨13 小时前
Kotlin 循环语句详解
android·java·开发语言·kotlin
Alex老夫子13 小时前
kotlin sortedBy 与sortedWith的区别
android·开发语言·kotlin