如果希望具有可为空的内容,则需要将声明设置为
@Composable
fun BottomSectionWrapper(
modifier: Modifier = Modifier,
content: @Composable (() -> Unit)? = null,
bottomSection: @Composable (() -> Unit)? = null,
) {
Column(modifier = modifier) {
content?.invoke()
bottomSection?.invoke()
}
}
您可以像在此演示中一样使用它
@Preview
@Composable
private fun BottomSectionWrapperTest() {
Column {
var isSet by remember {
mutableStateOf(false)
}
Button(onClick = { isSet = isSet.not() }) {
Text("isSet: $isSet")
}
val bottomSection: (@Composable () -> Unit)? = if (isSet) {
{
Box(modifier = Modifier.size(100.dp).background(Color.Green)) {
Text("Bottom Section")
}
}
} else null
BottomSectionWrapper(
modifier = Modifier.border(2.dp, Color.Red),
content = {
Text("Content Section")
},
bottomSection = bottomSection
)
}
}
如果您希望检测Composable是空的,还是有0.dp大小或任何大小,您可以使用Layout
,具有不同的方法、尺寸设置和放置选项.
第二个Modifier.layoutId
用于默认的合成体,如TextField
、Tab
@Composable
fun BottomSectionWrapperLayout(
modifier: Modifier = Modifier,
content: @Composable () -> Unit = {},
bottomSection: @Composable () -> Unit = {},
) {
Layout(
modifier = modifier,
contents = listOf(content, bottomSection)
) { measurables: List<List<Measurable>>, constraints: Constraints ->
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
val contentPlaceable: Placeable? =
measurables.first().firstOrNull()?.measure(looseConstraints)
val bottomSectionPlaceable: Placeable? =
measurables.last().firstOrNull()?.measure(looseConstraints)
println("content: $contentPlaceable, bottomSectionPlaceable: $bottomSectionPlaceable")
// you can set width and height as required, i make it as a Column
// this width and height determines whether it's a Column, Row or a Box
val contentWidth = contentPlaceable?.width ?: 0
val contentHeight = contentPlaceable?.height ?: 0
val bottomSectionWidth = bottomSectionPlaceable?.width ?: 0
val bottomSectionHeight = bottomSectionPlaceable?.height ?: 0
val totalWidth = if (constraints.hasFixedWidth && constraints.hasBoundedWidth)
constraints.maxWidth else contentWidth.coerceAtLeast(bottomSectionWidth)
.coerceIn(constraints.minWidth, constraints.maxWidth)
val totalHeight = if (constraints.hasFixedHeight && constraints.hasBoundedHeight)
constraints.maxHeight else (contentHeight + bottomSectionHeight)
.coerceIn(constraints.minHeight, constraints.maxHeight)
layout(totalWidth, totalHeight) {
// You can place them according to your logic here
contentPlaceable?.placeRelative(0, 0)
bottomSectionPlaceable?.placeRelative(0, contentHeight)
}
}
}
对于这Layout
,您可以通过判断Placeable是否为空(这意味着传递空的lambda)来检测它们中是否有任何一个为空,如果不为空,则可以判断它的大小.
@Preview
@Composable
private fun LayoutTest() {
Column(modifier = Modifier.fillMaxSize()) {
BottomSectionWrapperLayout(
modifier = Modifier.border(2.dp, Color.Red),
content = {
Text("Content Section")
},
bottomSection = {
Text("Bottom Section")
}
)
Spacer(Modifier.height(20.dp))
BottomSectionWrapperLayout(
modifier = Modifier.border(2.dp, Color.Red),
bottomSection = {
Text("Bottom Section")
}
)
Spacer(Modifier.height(20.dp))
BottomSectionWrapperLayout(
modifier = Modifier.border(2.dp, Color.Red),
content = {
Text("Content Section")
}
)
}
}
如果您查看println,您可以看到在每种情况下,您将能够看到哪些是空的,哪些不是.此外,您还可以获得可放置的尺寸.
另一个选项是创建此布局,就像Textfield在第495行中所做的那样.
https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/material/material/src/commonMain/kotlin/androidx/compose/material/TextField.kt;l=495?q=TextField&ss=androidx%2Fplatform%2Fframeworks%2Fsupport个
但是使用这种方法,您将无法判断是否传递了空lambda,因为当它不为空时,它被放在一个Box中.然而,这种方法经常被使用,因为您可以通过ID而不是判断列表来判断和比较内容.
@Composable
fun BottomSectionWrapperLayout2(
modifier: Modifier = Modifier,
content: @Composable (() -> Unit)? = null,
bottomSection: @Composable (() -> Unit)? = null,
) {
Layout(
modifier = modifier,
content = {
if (content != null) {
Box(
modifier = Modifier.layoutId("content")
) {
content()
}
}
if (bottomSection != null) {
Box(
modifier = Modifier.layoutId("bottomSection")
) {
bottomSection()
}
}
}
) { measurables: List<Measurable>, constraints: Constraints ->
val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0)
val contentPlaceable: Placeable? =
measurables.find { it.layoutId == "content" }?.measure(looseConstraints)
val bottomSectionPlaceable =
measurables.find { it.layoutId == "bottomSection" }?.measure(looseConstraints)
// you can set width and height as required, i make it as a Column
// this width and height determines whether it's a Column, Row or a Box
val contentWidth = contentPlaceable?.width ?: 0
val bottomSectionWidth = bottomSectionPlaceable?.width ?: 0
val contentHeight = contentPlaceable?.height ?: 0
val bottomSectionHeight = bottomSectionPlaceable?.height ?: 0
val totalWidth = if (constraints.hasFixedWidth && constraints.hasBoundedWidth)
constraints.maxWidth else contentWidth.coerceAtLeast(bottomSectionWidth)
.coerceIn(constraints.minWidth, constraints.maxWidth)
val totalHeight = if (constraints.hasFixedHeight && constraints.hasBoundedHeight)
constraints.maxHeight else (contentHeight + bottomSectionHeight)
.coerceIn(constraints.minHeight, constraints.maxHeight)
layout(totalWidth, totalHeight) {
contentPlaceable?.placeRelative(0, 0)
bottomSectionPlaceable?.placeRelative(0, contentHeight)
}
}
}
用法与其他布局相同.