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

相关推荐
移动开发者1号1 小时前
ReLinker优化So库加载指南
android·kotlin
山野万里__1 小时前
C++与Java内存共享技术:跨平台与跨语言实现指南
android·java·c++·笔记
Huckings1 小时前
Android 性能问题
android
移动开发者1号2 小时前
剖析 Systrace:定位 UI 线程阻塞的终极指南
android·kotlin
移动开发者1号2 小时前
深入解析内存抖动:定位与修复实战(Kotlin版)
android·kotlin
whysqwhw2 小时前
OkHttp深度架构缺陷分析与革命性演进方案
android
Zevalin爱灰灰4 小时前
MATLAB GUI界面设计 第六章——常用库中的其它组件
开发语言·ui·matlab
Digitally4 小时前
如何将文件从 iPhone 传输到 Android(新指南)
android·ios·iphone
前端开发与ui设计的老司机4 小时前
数字孪生技术引领UI前端设计潮流:增强现实(AR)的集成应用
ui
whysqwhw5 小时前
OkHttp深度架构缺陷分析与演进规划
android