找回密码
 立即注册
首页 业界区 业界 Jetpack Compose学习(16)——ModalBottomSheet(底部弹窗 ...

Jetpack Compose学习(16)——ModalBottomSheet(底部弹窗)

井晶灵 昨天 17:16
原文地址: Jetpack Compose学习(16)——ModalBottomSheet(底部弹窗)-Stars-One的杂货小窝
接手新公司项目里,有代码用到了这个弹窗,由于需要重构架构和进行相关统一组件封装,顺手学习下这个组件,发现还是踩了些坑(怪我以Compose里的Dialog来用了哈哈)
介绍

这个组件是属于M3里的组件,需要引入androidx.compose.material3这个依赖
不过新版本的Android Studio创建项目都是直接通过Bom引入了,是都会带有了这个依赖了(这里就不过多提及加入依赖了)
PS:主要是现在新版本Android Studio,新创建的项目,依赖分了几个文件,贴的话会很麻烦,见谅哈哈
  1. androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
复制代码
基本使用

效果:
1.gif

代码:
  1. import androidx.compose.foundation.layout.Arrangement
  2. import androidx.compose.foundation.layout.Column
  3. import androidx.compose.foundation.layout.statusBarsPadding
  4. import androidx.compose.material3.Button
  5. import androidx.compose.material3.ExperimentalMaterial3Api
  6. import androidx.compose.material3.ModalBottomSheet
  7. import androidx.compose.material3.Text
  8. import androidx.compose.material3.rememberModalBottomSheetState
  9. import androidx.compose.runtime.Composable
  10. import androidx.compose.runtime.getValue
  11. import androidx.compose.runtime.mutableStateOf
  12. import androidx.compose.runtime.rememberCoroutineScope
  13. import androidx.compose.runtime.saveable.rememberSaveable
  14. import androidx.compose.runtime.setValue
  15. import androidx.compose.ui.Alignment
  16. import androidx.compose.ui.Modifier
  17. import androidx.compose.ui.platform.LocalContext
  18. import androidx.compose.ui.unit.dp
  19. import kotlinx.coroutines.launch
  20. @OptIn(ExperimentalMaterial3Api::class)
  21. @Composable
  22. fun ModelSheetDemoPage(modifier: Modifier = Modifier) {
  23.     val context = LocalContext.current
  24.     Column(modifier = Modifier.statusBarsPadding()) {
  25.         var openBottomSheet by rememberSaveable { mutableStateOf(false) }
  26.         val scope = rememberCoroutineScope()
  27.         val bottomSheetState = rememberModalBottomSheetState()
  28.         // App content
  29.         Column(
  30.             horizontalAlignment = Alignment.Start,
  31.             verticalArrangement = Arrangement.spacedBy(4.dp)
  32.         ) {
  33.             Button(
  34.                 onClick = { openBottomSheet = !openBottomSheet },
  35.                 modifier = Modifier.align(Alignment.CenterHorizontally)
  36.             ) {
  37.                 Text(text = "Show Bottom Sheet")
  38.             }
  39.         }
  40.         // Sheet content
  41.         if (openBottomSheet) {
  42.             ModalBottomSheet(
  43.                 onDismissRequest = { openBottomSheet = false },
  44.                 sheetState = bottomSheetState,
  45.             ) {
  46.                 Text("内容数据")
  47.                 Button(
  48.                     // Note: If you provide logic outside of onDismissRequest to remove the sheet,
  49.                     // you must additionally handle intended state cleanup, if any.
  50.                     onClick = {
  51.                         scope
  52.                             .launch { bottomSheetState.hide() }
  53.                             .invokeOnCompletion {
  54.                                 if (!bottomSheetState.isVisible) {
  55.                                     openBottomSheet = false
  56.                                 }
  57.                             }
  58.                     }
  59.                 ) {
  60.                     Text("Hide Bottom Sheet")
  61.                 }
  62.             }
  63.         }
  64.     }
  65. }
复制代码
这里需要注意的是:

  • 展示弹窗,实际和Dialog类似,也是控制一个Boolean数值变化从而弹出
  • 关闭弹窗的代码得用上面的写法,否则就是没有下滑效果!!(之前就是在这踩坑了,虽然没人关注这点哈哈)
PS:后续代码为了保证重点和观感,会有所精简
ModalBottomSheet默认是有半屏和全屏模式的,但上面例子由于我们的内容元素不多,高度不是大,我们改造下,加个LazyColumn再看下效果
效果:
2.gif

代码:
  1. ModalBottomSheet(
  2.         onDismissRequest = { openBottomSheet = false },
  3.         sheetState = bottomSheetState,
  4. ) {
  5.         //....
  6.         LazyColumn {
  7.                 items(20) {
  8.                         Row(modifier= Modifier.fillMaxWidth().height(48.dp).padding(horizontal = 24.dp), verticalAlignment = Alignment.CenterVertically) {
  9.                                 Text("hello ${it}")
  10.                         }
  11.                 }
  12.         }
  13. }
复制代码
自定义样式

去掉小横条

想要实现自定义的下拉样式,然后,不希望要这个小横条(如下图所示),要如何实现呢?
3.png

可以通过dragHandle属性来实现,如下代码
  1. ModalBottomSheet(
  2.         onDismissRequest = { openBottomSheet = false },
  3.         sheetState = bottomSheetState,
  4.         dragHandle = {} //设置为空
  5. ) {
  6.        
  7. }
复制代码
效果如下:
4.png

顶头区自定义按钮

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

代码:
  1. ModalBottomSheet(
  2.         onDismissRequest = { openBottomSheet = false },
  3.         sheetState = bottomSheetState,
  4.         dragHandle = {
  5.                 Row(modifier= Modifier.fillMaxWidth().padding(horizontal = 24.dp)) {
  6.                         Text("取消",modifier= Modifier.clickable{
  7.                                 scope
  8.                                         .launch { bottomSheetState.hide() }
  9.                                         .invokeOnCompletion {
  10.                                                 if (!bottomSheetState.isVisible) {
  11.                                                         openBottomSheet = false
  12.                                                 }
  13.                                         }
  14.                         })
  15.                         Spacer(modifier= Modifier.weight(1f))
  16.                         Text("确定",modifier= Modifier.clickable{
  17.                                 scope
  18.                                         .launch { bottomSheetState.hide() }
  19.                                         .invokeOnCompletion {
  20.                                                 if (!bottomSheetState.isVisible) {
  21.                                                         openBottomSheet = false
  22.                                                 }
  23.                                         }
  24.                         })
  25.                 }
  26.         }
  27. )
复制代码
禁止展示半屏

如果不想要展示半屏的效果,可以通过下面这样设置
  1. val bottomSheetState = rememberModalBottomSheetState(true)
复制代码
意思是,如果你的内容满全屏了,则直接跳过半屏模式,直接展示全屏,效果如下图展示
6.gif

那我内容元素总高度不满全屏高度,又该如何呢?
那更简单,直接将你的内容容器用Modifier设置为全屏即可
  1. ModalBottomSheet(
  2.         onDismissRequest = { openBottomSheet = false },
  3.         sheetState = bottomSheetState,
  4. ) {
  5.         //直接填充满屏即可!
  6.         Column(modifier= Modifier.fillMaxSize()) {
  7.                 Text("内容数据")
  8.                 Button(
  9.                         // Note: If you provide logic outside of onDismissRequest to remove the sheet,
  10.                         // you must additionally handle intended state cleanup, if any.
  11.                         onClick = {
  12.                                 scope
  13.                                         .launch { bottomSheetState.hide() }
  14.                                         .invokeOnCompletion {
  15.                                                 if (!bottomSheetState.isVisible) {
  16.                                                         openBottomSheet = false
  17.                                                 }
  18.                                         }
  19.                         }
  20.                 ) {
  21.                         Text("Hide Bottom Sheet")
  22.                 }
  23.         }
  24. }
复制代码
参考


  • Bottom sheets  |  Jetpack Compose  |  Android Developers

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册