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")
 }
 }
 }
 }
}

这里需要注意的是:

  1. 展示弹窗,实际和Dialog类似,也是控制一个Boolean数值变化从而弹出
  2. 关闭弹窗的代码得用上面的写法,否则就是没有下滑效果!!(之前就是在这踩坑了,虽然没人关注这点哈哈)

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")
	}
	}
}

参考

作者:Stars-one原文地址:https://www.cnblogs.com/stars-one/p/18979413

%s 个评论

要回复文章请先登录注册