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

相关推荐
Anesthesia丶1 小时前
Vue3 + naive-ui + fastapi使用心得
vue.js·ui·fastapi
*拯1 小时前
Uniapp Android/IOS 获取手机通讯录
android·ios·uni-app
编程乐趣3 小时前
点下4个Winform UI开源控件库
ui·开源·mfc
天天打码4 小时前
Lynx-字节跳动跨平台框架多端兼容Android, iOS, Web 原生渲染
android·前端·javascript·ios
lilili啊啊啊6 小时前
iOS safari和android chrome开启网页调试与检查器的方法
android·ios·safari
Blue.ztl8 小时前
菜鸟之路day31一一MySQL之多表设计
android·数据库·mysql
练习本11 小时前
Android系统架构模式分析
android·java·架构·系统架构
每次的天空16 小时前
Kotlin 内联函数深度解析:从源码到实践优化
android·开发语言·kotlin
练习本17 小时前
Android MVC架构的现代化改造:构建清晰单向数据流
android·架构·mvc
早上好啊! 树哥17 小时前
android studio开发:设置屏幕朝向为竖屏,强制应用的包体始终以竖屏(纵向)展示
android·ide·android studio