Mar*_*ron 3 android kotlin android-jetpack-compose
我在 Compose 中有一个“简单”布局,其中 aColumn有两个元素:
我希望布局具有以下行为:
screenWidth200.dp这意味着如果方块中的文本很短,则图像将覆盖顶部的大方块。但如果任何方形文本真的很长,我希望整个网格放大和缩小图像。这些是理想的结果:


我已经ConstraintLayout在 Compose 中尝试过此操作,但无法使正方形正确缩放。
使用 a 时Column,我无法获得随大内容一起增长的选项 - 文本只是被截断,而图像仍然是一个巨大的正方形。
这些是我构建的组件:
// the screen
Column {
    Box(modifier = Modifier
        .heightIn(min = 200.dp, max = screenWidth)
        .aspectRatio(1f)
        .border(BorderStroke(1.dp, Color.Green))
        .align(Alignment.CenterHorizontally),
    ) {
        Image(
            painter = painterResource(id = R.drawable.puppy),
            contentDescription = null,
            contentScale = ContentScale.Crop
        )
    }
    OptionsGrid(choicesList, modifier = Modifier.heightIn(max = screenHeight - 200.dp))
}
@Composable
fun OptionsGrid(choicesList: List<List<String>>, modifier: Modifier = Modifier) {
    Column(
        modifier = modifier
            .border(1.dp, Color.Blue)
            .padding(top = 4.dp, bottom = 4.dp)
            .fillMaxHeight(),
        verticalArrangement = Arrangement.Center
    ) {
        choicesList.forEach { choicesPair ->
            Row(modifier = Modifier.weight(0.5f)) {
                choicesPair.forEach { choice ->
                    Box(
                        modifier = Modifier
                            .padding(4.dp)
                            .background(Color.White)
                            .weight(0.5f)
                    ) {
                        Option(choice = choice)
                    }
                }
            }
        }
    }
}
@Composable
fun Option(choice: String) {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Yellow)
            .border(BorderStroke(1.dp, Color.Red)),
        contentAlignment = Alignment.Center
    ) {
        Text(
            text = choice,
            modifier = Modifier.padding(8.dp),
            textAlign = TextAlign.Center,
        )
    }
}
我需要为此定制布局吗?我想这里发生的事情是Column首先测量图像,让它成为其最大高度,因为屏幕上有空间,然后在测量网格时,它给出了剩余的空间,仅此而已。
所以我需要一个从底部开始测量的布局?
以下是无需自定义布局即可实现的方法。
您需要在之后计算图像尺寸OptionsGrid。在这种情况下,您可以使用Modifier.weight(1f, fill = false):它强制所有视图不在Modifier.weight任何加权元素之前进行布局。
Modifier.weight将覆盖您的Modifier.heightIn,但我们可以从另一侧限制它的大小:使用Modifier.layouton OptionsGrid。使用此修饰符,我们可以覆盖应用于视图的约束。
psModifier.heightIn(max = screenWidth)是多余的,因为视图无论如何都不会增长超过屏幕大小,除非宽度约束被覆盖,例如使用滚动视图。
.height(IntrinsicSize.Min)将停止OptionsGrid增长超过需要。请注意,应将其放置在 后面Modifier.layout,因为它将高度约束设置为无穷大。了解修饰符顺序为何如此重要。
val choicesList = listOf(
    listOf(
        LoremIpsum(if (flag) 100 else 1).values.first(),
        "Short stuff",
    ),
    listOf(
        "Medium length text",
        "Hi",
    ),
)
Column {
    Box(
        modifier = Modifier
            .weight(1f, fill = false)
            .aspectRatio(1f)
            .border(BorderStroke(1.dp, Color.Green))
            .align(Alignment.CenterHorizontally)
    ) {
        Image(
            painter = painterResource(id = R.drawable.profile),
            contentDescription = null,
            contentScale = ContentScale.Crop
        )
    }
    OptionsGrid(
        choicesList,
        modifier = Modifier
            .layout { measurable, constraints ->
                val placeable = measurable.measure(constraints.copy(
                    // left 200.dp for min image height
                    maxHeight = constraints.maxHeight - 200.dp.roundToPx(),
                    // occupy all height except full image square in case of smaller text
                    minHeight = constraints.maxHeight - constraints.maxWidth,
                ))
                layout(placeable.width, placeable.height) {
                    placeable.place(0, 0)
                }
            }
            .height(IntrinsicSize.Min)
    )
}
结果:

| 归档时间: | 
 | 
| 查看次数: | 8021 次 | 
| 最近记录: |