Jetpack Compose学习(16)——ModalBottomSheet(底部弹窗)
原文地址: Jetpack Compose学习(16)——ModalBottomSheet(底部弹窗)-Stars-One的杂货小窝
接手新公司项目里,有代码用到了这个弹窗,由于需要重构架构和进行相关统一组件封装,顺手学习下这个组件,发现还是踩了些坑(怪我以Compose里的Dialog来用了哈哈)
介绍
这个组件是属于M3里的组件,需要引入androidx.compose.material3这个依赖
不过新版本的Android Studio创建项目都是直接通过Bom引入了,是都会带有了这个依赖了(这里就不过多提及加入依赖了)
PS:主要是现在新版本Android Studio,新创建的项目,依赖分了几个文件,贴的话会很麻烦,见谅哈哈
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
基本使用
效果:

代码:
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ModelSheetDemoPage(modifier: Modifier = Modifier) {
val context = LocalContext.current
Column(modifier = Modifier.statusBarsPadding()) {
var openBottomSheet by rememberSaveable { mutableStateOf(false) }
val scope = rememberCoroutineScope()
val bottomSheetState = rememberModalBottomSheetState()
// App content
Column(
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
Button(
onClick = { openBottomSheet = !openBottomSheet },
modifier = Modifier.align(Alignment.CenterHorizontally)
) {
Text(text = "Show Bottom Sheet")
}
}
// Sheet content
if (openBottomSheet) {
ModalBottomSheet(
onDismissRequest = { openBottomSheet = false },
sheetState = bottomSheetState,
) {
Text("内容数据")
Button(
// Note: If you provide logic outside of onDismissRequest to remove the sheet,
// you must additionally handle intended state cleanup, if any.
onClick = {
scope
.launch { bottomSheetState.hide() }
.invokeOnCompletion {
if (!bottomSheetState.isVisible) {
openBottomSheet = false
}
}
}
) {
Text("Hide Bottom Sheet")
}
}
}
}
}
这里需要注意的是:
- 展示弹窗,实际和Dialog类似,也是控制一个Boolean数值变化从而弹出
- 关闭弹窗的代码得用上面的写法,否则就是没有下滑效果!!(之前就是在这踩坑了,虽然没人关注这点哈哈)
PS:后续代码为了保证重点和观感,会有所精简
ModalBottomSheet默认是有半屏和全屏模式的,但上面例子由于我们的内容元素不多,高度不是大,我们改造下,加个LazyColumn再看下效果
效果:

代码:
ModalBottomSheet(
onDismissRequest = { openBottomSheet = false },
sheetState = bottomSheetState,
) {
//....
LazyColumn {
items(20) {
Row(modifier= Modifier.fillMaxWidth().height(48.dp).padding(horizontal = 24.dp), verticalAlignment = Alignment.CenterVertically) {
Text("hello ${it}")
}
}
}
}
自定义样式
去掉小横条
想要实现自定义的下拉样式,然后,不希望要这个小横条(如下图所示),要如何实现呢?

可以通过dragHandle属性来实现,如下代码
ModalBottomSheet(
onDismissRequest = { openBottomSheet = false },
sheetState = bottomSheetState,
dragHandle = {} //设置为空
) {
}
效果如下:

顶头区自定义按钮
这个dragHandle实际就是顶头那篇区域,如果想要自定义一个取消和确定,也可以实现,如下效果和代码
效果:

代码:
ModalBottomSheet(
onDismissRequest = { openBottomSheet = false },
sheetState = bottomSheetState,
dragHandle = {
Row(modifier= Modifier.fillMaxWidth().padding(horizontal = 24.dp)) {
Text("取消",modifier= Modifier.clickable{
scope
.launch { bottomSheetState.hide() }
.invokeOnCompletion {
if (!bottomSheetState.isVisible) {
openBottomSheet = false
}
}
})
Spacer(modifier= Modifier.weight(1f))
Text("确定",modifier= Modifier.clickable{
scope
.launch { bottomSheetState.hide() }
.invokeOnCompletion {
if (!bottomSheetState.isVisible) {
openBottomSheet = false
}
}
})
}
}
)
禁止展示半屏
如果不想要展示半屏的效果,可以通过下面这样设置
val bottomSheetState = rememberModalBottomSheetState(true)
意思是,如果你的内容满全屏了,则直接跳过半屏模式,直接展示全屏,效果如下图展示

那我内容元素总高度不满全屏高度,又该如何呢?
那更简单,直接将你的内容容器用Modifier设置为全屏即可
ModalBottomSheet(
onDismissRequest = { openBottomSheet = false },
sheetState = bottomSheetState,
) {
//直接填充满屏即可!
Column(modifier= Modifier.fillMaxSize()) {
Text("内容数据")
Button(
// Note: If you provide logic outside of onDismissRequest to remove the sheet,
// you must additionally handle intended state cleanup, if any.
onClick = {
scope
.launch { bottomSheetState.hide() }
.invokeOnCompletion {
if (!bottomSheetState.isVisible) {
openBottomSheet = false
}
}
}
) {
Text("Hide Bottom Sheet")
}
}
}
参考
Jetpack Compose学习(16)——ModalBottomSheet(底部弹窗)的更多相关文章
- Jetpack Compose学习(7)——MD样式架构组件Scaffold及导航底部菜单
Jetpack Compose学习(7)--MD样式架构组件Scaffold及导航底部菜单 | Stars-One的杂货小窝 Compose给我们提供了一个Material Design样式的首页组件 ...
- Jetpack Compose学习(3)——图标(Icon) 按钮(Button) 输入框(TextField) 的使用
原文地址: Jetpack Compose学习(3)--图标(Icon) 按钮(Button) 输入框(TextField) 的使用 | Stars-One的杂货小窝 本篇分别对常用的组件:图标(Ic ...
- Jetpack Compose学习(5)——从登录页美化开始学习布局组件使用
原文:Jetpack Compose学习(5)--从登录页美化开始学习布局组件使用 | Stars-One的杂货小窝 本篇主要讲解常用的布局,会与原生Android的布局控件进行对比说明,请确保了解A ...
- Jetpack Compose学习(6)——关于Modifier的妙用
原文: Jetpack Compose学习(6)--关于Modifier的妙用 | Stars-One的杂货小窝 之前学习记录中也是陆陆续续地将常用的Modifier的方法穿插进去了,本期就来详细的讲 ...
- Jetpack Compose学习(4)——Image(图片)使用及Coil图片异步加载库使用
原文地址 Jetpack Compose学习(4)--Image(图片)使用及Coil图片异步加载库使用 | Stars-One的杂货小窝 本篇讲解下关于Image的使用及使用Coil开源库异步加载网 ...
- Jetpack Compose学习(9)——Compose中的列表控件(LazyRow和LazyColumn)
原文:Jetpack Compose学习(9)--Compose中的列表控件(LazyRow和LazyColumn) - Stars-One的杂货小窝 经过前面的学习,大致上已掌握了compose的基 ...
- Jetpack Compose学习(11)——Navigation页面导航的使用
原文:Jetpack Compose学习(11)--Navigation页面导航的使用 - Stars-One的杂货小窝 在Android原生的View开发中的,也是有Navigation,原生我之后 ...
- Jetpack Compose学习(1)——从登录页开始入门
原文地址:Jetpack Compose学习(1)--从登录页开始入门 | Stars-One的杂货小窝 Jetpack Compose UI在前几天出了1.0正式版,之前一直还在观望,终于是出了正式 ...
- Jetpack Compose学习(2)——文本(Text)的使用
原文: Jetpack Compose学习(2)--文本(Text)的使用 | Stars-One的杂货小窝 对于开发来说,文字最为基础的组件,我们先从这两个使用开始吧 本篇涉及到Kotlin和DSL ...
- Jetpack Compose学习(8)——State及remeber
原文地址: Jetpack Compose学习(8)--State状态及remeber关键字 - Stars-One的杂货小窝 之前我们使用TextField,使用到了两个关键字remember和mu ...
随机推荐
- Fast Prefix Sum Implementation Using Subgroups in GLSL Compute Shaders
利用 Vulkan 1.1 的 subgroup 特性加速 ComputeShader 的前缀和计算,参考: Vulkan Subgroup Tutorial - Khronos Blog - The ...
- DotNetGuide 突破了 8K + Star,努力打造C#/.NET/.NET Core全面的学习、工作、面试指南知识库!
前言 转眼之间维护DotNetGuide(全面的C#/.NET/.NET Core学习.工作.面试指南知识库)已经持续超过了4年多的时间,Commit提交数也超过1400+,在前几天在 GitHub ...
- Java连接Redis常用操作
1.去重 package Data; import redis.clients.jedis.Jedis; public class TestRedisUniq { public static Jedi ...
- 华为od机考2025A卷真题 -寻找重复代码
题目描述与示例 题目 小明负责维护项目下的代码,需要查找出重复代码,用以支撑后续的代码优化,请你帮助小明找出重复的代码. 重复代码查找方法:以字符串形式给出两行代码text1,text2(字符串长度1 ...
- selenium IDE简单使用
selenium IDE可理解为录制操作浏览器的过程,然后回放实现UI级的自动化 一,首先安装,本案例主要在谷歌浏览器上使用,所以用的是支持谷歌的IDE文件 下载,打开https://www.crx4 ...
- 康谋分享 | 3DGS:革新自动驾驶仿真场景重建的关键技术
登录后复制 随着自动驾驶技术的迅猛发展,构建高保真.动态的仿真场景成为了行业的迫切需求.传统的三维重建方法在处理复杂场景时常常面临效率和精度的挑战.在此背景下,3D高斯点阵渲染(3DGS)技术应运而生 ...
- MySQL 的存储引擎有哪些?它们之间有什么区别?
MySQL 的存储引擎及其区别 MySQL 提供多种存储引擎,不同存储引擎在数据存储方式.索引支持.事务处理等方面各具特点.以下列出常用的存储引擎及其主要区别. 1. 常见存储引擎 (1)InnoDB ...
- 在win nginx下配置symfony3.4,并隐藏项目名称 .php入口
在win nginx下配置symfony3.4,并隐藏项目名称 .php入口 记录下 # power by www.php.cn #user nobody; worker_processes 1; ...
- K8s新手系列之Pod的重启策略
概述 K8s中Pod的重启策略具有确保服务连续性.保证任务完整性.提升资源利用效率.便于故障排查的作用 Pod的重启策略可以根据restartPolicy字段定义. 重启策略适用于pod对象中的所有容 ...
- Sentinel——网关限流
目录 网关限流 route维度 自定义异常 重定向 自定义结果 API维度 网关限流代码配置 网关限流 Sentinel 支持对 Spring Cloud Gateway.Zuul 等主流的 API ...