Compose封装Drop形式popwindow
compose 提供Popup组件包含属性如下
@Composable
fun Popup(
alignment: Alignment = Alignment.TopStart,
offset: IntOffset = IntOffset(0, 0),
onDismissRequest: (() -> Unit)? = null,
properties: PopupProperties = PopupProperties(),
content: @Composable () -> Unit
)
- alignment控制显示位置
- offset控制x,y偏移量
- onDismissRequest 监听取消动作
- properties控制弹框外边缘是否可取消是否强弹框
- content绘制弹框内容
存在问题位置锚点和偏移量调整麻烦,官网提供一种约束布局ConstraintLayout满足对齐不过针对的是控件,所以在Popup外套一层布局比如Box在用包裹特性包裹Popup
- 封装简单Popup满足列表格式单选
@Composable
fun dropPopWindow(
isShowPop: MutableState<Boolean>,
array: Array<String>,
alignment: Alignment = Alignment.TopStart,
offset: IntOffset = IntOffset(0, 0), onItemClick: (Int) -> Unit
) {
if (isShowPop.value) {
Popup(
content = {
Surface(
shadowElevation = 8.dp,
tonalElevation = 8.dp,
shape = RoundedCornerShape(8.dp)
) {
Column(
modifier = Modifier
.background(
Color.White,
RoundedCornerShape(6.dp)
)
.width(170.dp)
) {
array.forEachIndexed { index, s ->
Row(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.clickable {
isShowPop.value = false
onItemClick(index)
}, verticalAlignment = CenterVertically
) {
Spacer(modifier = Modifier.width(23.dp))
Text(
s,
fontSize = TextUnit(16f, TextUnitType.Sp),
modifier = Modifier
.padding(12.dp, 12.dp)
)
}
}
}
}
},
properties = PopupProperties(dismissOnBackPress = true, dismissOnClickOutside = false),
onDismissRequest = {
isShowPop.value = false
},
alignment = alignment,
offset = offset
)
}
}
- 给Popup套壳并且和Button关联(也可以是其他组件关联)存放在约束布局中
ConstraintLayout位置关联方法Modifier.constrainAs,这里使用组件位于Button正下方,示例如下
ConstraintLayout {
var popState by remember {
mutableStateOf(mutableStateOf(false))
}
val (center, desc) = createRefs()
Button(onClick = {
popState.value = true
}, modifier = Modifier.constrainAs(center) {
centerTo(parent)
}) {
Text(text = "Center")
}
val context = LocalContext.current
if (popState.value) {
Box(modifier = Modifier
.constrainAs(desc) {
top.linkTo(center.bottom)
start.linkTo(parent.start)
end.linkTo(parent.end)
}
.wrapContentSize()) {
dropPopWindow(
isShowPop = popState,
array = arrayOf("Item1", "Item2", "Item3"),
onItemClick = {
Toast.makeText(context, "点击了$it", Toast.LENGTH_SHORT).show()
}, alignment = Alignment.TopCenter, offset = IntOffset.Zero
)
}
}
}
效果如图:
Compose封装Bottom Sheet形式popwindow列表单选
这里选择布局组件ModalDrawerSheet进行封装,先介绍官方组件
@Composable
fun ModalDrawerSheet(
modifier: Modifier = Modifier,-要应用于此抽屉内容的修饰符
drawerShape: Shape = DrawerDefaults.shape,-定义此抽屉容器的形状
drawerContainerColor: Color = MaterialTheme.colorScheme.surface,-用于此抽屉背景的颜色。使用颜色。透明表示没有颜色。
drawerContentColor: Color = contentColorFor(drawerContainerColor),-此抽屉中内容的首选颜色。默认为drawerContainerColor的匹配内容颜色,或者不是主题中的颜色,则默认为当前LocalContentColor。
drawerTonalElevation: Dp = DrawerDefaults.ModalDrawerElevation,-当drawerContainerColor为ColorScheme.surface时,半透明的原色覆盖将应用于容器顶部。色调高程值越高,浅色主题的颜色越深,深色主题的颜色就越浅。另请参见:曲面。
windowInsets: WindowInsets = DrawerDefaults.windowInsets,-类似于边距
content: @Composable ColumnScope.() -> Unit-模态导航抽屉内的内容
)
默认content内容是铺满全屏的,设想用比重关系切割内容和背景板背景板设置半透明遮罩,是弹框还得补充标题和关闭按钮。用Box作为遮罩部分背景色设置0x80000000,用LazyColumn存放标题关闭按钮和列表内容主体
@Composable
fun BottomSheetPopWindow(
title: String = "请选择",
isShowPop: MutableState<Boolean>,
array: Array<String>,
onItemClick: (Int) -> Unit,
onOutSideDismiss: (MutableState<Boolean>) -> Unit
) {
if (isShowPop.value) {
ModalDrawerSheet(
modifier = Modifier
.fillMaxSize(),
drawerShape = RoundedCornerShape(0.dp),
drawerContainerColor = Color(0x80000000),
windowInsets = WindowInsets(0.dp)
) {
Box(
Modifier
.fillMaxWidth()
.weight(1f, true).clickable { onOutSideDismiss(isShowPop) }
) {
}
val h = LocalConfiguration.current.screenHeightDp
LazyColumn(
contentPadding = PaddingValues(horizontal = 12.dp),
verticalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.defaultMinSize(minHeight = h.div(3).dp)
.background(Color.White, RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp))
) {
item {
Box(
Modifier
.fillMaxWidth()
.height(60.dp)
) {
Text(
text = title,
color = Color.Black,
fontWeight = FontWeight.Bold,
fontSize = TextUnit(16f, TextUnitType.Sp),
modifier = Modifier.align(Center)
)
Image(
imageVector = Icons.Default.Close,
contentDescription = null,
modifier = Modifier
.align(
CenterEnd
)
.size(48.dp)
.clickable {
isShowPop.value = false
},
contentScale = ContentScale.Inside
)
}
}
items(array.size) {
TextButton(
onClick = {
isShowPop.value = false
onItemClick(it)
}, modifier = Modifier
.fillMaxWidth()
.height(48.dp)
) {
Text(
text = array[it],
color = Color.DarkGray,
fontSize = TextUnit(15f, TextUnitType.Sp)
)
}
}
}
}
}
}
引用方式
BottomSheetPopWindow(
isShowPop = popState,
array = arrayOf("Item1", "Item2", "Item3"),
onItemClick = {
Toast.makeText(context, "点击了$it", Toast.LENGTH_SHORT).show()
},
onOutSideDismiss = {
it.value = false
})
实现效果
实现底部弹框还存在很多方式,特别场景还需要弹出动画,需要可自行去官网学习