在这种情况下,如果Button
始终大于Text
,则不需要Layout
,并且它首先出现在获取Content Size和的位置.
你可以从Modifier.onSizeChanged/onGloballyPositioned/onPlaced
号到Button
号.
你可以这样做
@Composable
fun MyComposable(
modifier: Modifier = Modifier,
state: LayoutState,
button: @Composable () -> Unit,
) {
val density = LocalDensity.current
Box(modifier = modifier) {
var contentSize by remember {
mutableStateOf(DpSize.Zero)
}
when (state) {
LayoutState.Button -> {
Box(
modifier = Modifier.onSizeChanged { size: IntSize ->
contentSize = with(density) {
size.toSize().toDpSize()
}
}
){
button()
}
}
LayoutState.Text -> {
// enforce text view to have maxWidth and maxHeight
Text(
modifier = modifier.size(contentSize),
text = "Some Text"
)
}
}
}
}
Extra
当你不知道哪种合成物更大的时候
如果你想使用一个布局,你可以拥有两个子组件而不是空的,而且使用这种方法,你不需要额外的重新组合来获得容器的设置大小来匹配最大大小,这样它就不会在状态改变时改变大小.
https://stackoverflow.com/a/73357119/5457853个
如果设置为Layout
,您可以获得最大尺寸,并根据状态只放置其中一个尺寸.当你不知道哪个Composable可以更大的时候,你可以使用这个Layout
,这也适用于这个问题,就像它适用于任何Composable一样.
enum class LayoutState {
Button, Text
}
以及实现测量最大尺寸的布局.在这个示例中,我使用文本自己的尺寸来测量文本,但如果按钮尺寸可用,您可以用Constraints.Fixed()
而不是looseConstraints
来测量它.
@Composable
private fun MyLayout(
modifier: Modifier = Modifier,
layoutState: LayoutState,
button: @Composable (() -> Unit)? = null,
text: @Composable (() -> Unit)? = null
) {
val measurePolicy = remember(layoutState) {
object : MeasurePolicy {
override fun MeasureScope.measure(
measurables: List<Measurable>,
constraints: Constraints
): MeasureResult {
val looseConstraints = constraints.copy(
minWidth = 0,
minHeight = 0
)
val buttonPlaceable = measurables.firstOrNull { it.layoutId == "button" }
?.measure(looseConstraints)
val buttonWidth = buttonPlaceable?.width ?: 0
val buttonHeight = buttonPlaceable?.height ?: 0
val textPlaceable = measurables.firstOrNull { it.layoutId == "text" }
?.measure(looseConstraints)
val textWidth = textPlaceable?.width ?: 0
val textHeight = textPlaceable?.height ?: 0
val layoutWidth = buttonWidth.coerceAtLeast(textWidth)
val layoutHeight = buttonHeight.coerceAtLeast(textHeight)
return layout(layoutWidth, layoutHeight) {
val placeable = if (layoutState == LayoutState.Button) {
buttonPlaceable
} else {
textPlaceable
}
placeable?.let {
// This is for centering Placeable inside Container
val xPos = (layoutWidth - placeable.width) / 2
val yPos = (layoutHeight - placeable.height) / 2
placeable.placeRelative(xPos, yPos)
}
}
}
}
}
Layout(
modifier = modifier,
content = {
if (button != null) {
Box(modifier = Modifier.layoutId("button")) {
button()
}
}
if (text != null) {
Box(modifier = Modifier.layoutId("text")) {
text()
}
}
},
measurePolicy = measurePolicy
)
}
用法
@Preview
@Composable
private fun LayoutTest() {
var layoutState by remember {
mutableStateOf(LayoutState.Button)
}
Column {
Button(
onClick = {
if (layoutState == LayoutState.Button) {
layoutState = LayoutState.Text
} else {
layoutState = LayoutState.Button
}
}
) {
Text("State: $layoutState")
}
MyLayout(
modifier = Modifier.border(2.dp, Color.Red),
layoutState = layoutState,
button = {
Button(
onClick = {
}
) {
Text("Some Button")
}
},
text = {
Text("Some Text")
}
)
Spacer(modifier = Modifier.height(20.dp))
MyLayout(
modifier = Modifier.border(2.dp, Color.Red),
layoutState = layoutState,
button = {
Button(
modifier = Modifier.size(200.dp),
onClick = {
}
) {
Text("Some Button")
}
},
text = {
Text("Some Text")
}
)
Spacer(modifier = Modifier.height(20.dp))
MyLayout(
modifier = Modifier.border(2.dp, Color.Red),
layoutState = layoutState,
button = {
Button(
onClick = {
}
) {
Text("Some Button")
}
},
text = {
Text(
"Some Text",
modifier = Modifier.width(160.dp).height(60.dp).background(Color.Red),
color = Color.White,
textAlign = TextAlign.Center
)
}
)
}
}
在这两种情况下,我们都用它们自己的大小来衡量每个可合成material ,但容器的大小是最大的.如果您想重新测量包含所有空间的较小的一个,您可以使用SubcomposeLayout
How to adjust size of component to it's child and remain unchanged when it's child size will change? (Jetpack Compose)