自定义布局 Android 组成可测量的宽度

Custom Layout Android Compose measurable width

我正在尝试在 Android 中实现自定义“行”布局,如​​下所示:

@Composable
fun CustomLayout(modifier: Modifier, content: @Composable () -> Unit){
    Layout(
        modifier = modifier,
        content = content,
    ) { measurables, constraints ->
        val placeables = measurables.map { measurable ->
          measurable.measure(constraints)
        }
        var xPos = 0

        layout(constraints.maxWidth, constraints.maxHeight) {
            placeables.forEach { placeable ->
                placeable.placeRelative(x = xPos, y = 0)
                xPos += placeable.width
            }
        }
    }

}

这是此可组合项的预览:

@Preview(name = "Preview")
@Composable
fun customLayoutPreview() {
    CustomLayout(Modifier.size(1080.dp,100.dp)){
        Box(
            Modifier
                .size(32.dp, 64.dp)
                .background(Color.Red)) {

        }
        Box(
            Modifier
                .size(100.dp, 64.dp)
                .background(Color.Green)) {

        }
        Box(
            Modifier
                .size(32.dp, 64.dp)
                .background(Color.Yellow)) {

        }
    }
}

这里的问题是每个 measurable(盒子)在测量后得到 parent 宽度,因此是 1080dp,而不是传递给盒子的所需宽度,这导致第一个 child 取全部 space.

见: Preview

理论上的预期是什么: (方框 32dp)(方框 100dp)(方框 32dp)

我在这里缺少什么?

我尝试了文档,但我无法理解如何实现像普通 android 自定义 ViewGroup.onMeasure 这样的东西: view.measure(MeasureSpec.makeMeasureSpec(wantedSize, AT_MOST or EXACT)),其中 wantedSize 可以从 LayoutParams 或 WRAP_CONTENT 策略中获取。

环境: Android 北极狐工作室。 撰写:1.0.0。 科特林:1.5.10。 AGP 和 Gradle:7.0.0.

好的,你不应该在那边使用 placeable.measuredWidth。只需将其替换为 placeable.width。此外,在您的映射逻辑中,您根本不需要 val。就这样做

val placeables = measurables.map {
           it.measure(constraints)    
        }

访问此处了解详情

https://developer.android.com/codelabs/jetpack-compose-layouts?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fcompose%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fjetpack-compose-layouts#6

您必须复制您的约束并将最小值更改为 0。像这样更改它:

@Composable
fun CustomLayout(modifier: Modifier, content: @Composable () -> Unit) {
    Layout(
        modifier = modifier,
        content = content,
    ) { measurables, constraints ->
        // MAKE A COPY WITH 0 FOR MIN
        val looseConstraints = constraints.copy(
            minWidth = 0,
            minHeight = 0
        )
        val placeables = measurables.map { measurable ->
            measurable.measure(looseConstraints)
        }
        var xPos = 0

        layout(constraints.maxWidth, constraints.maxHeight) {
            placeables.forEach { placeable ->
                placeable.placeRelative(x = xPos, y = 0)
                xPos += placeable.width
            }
        }
    }
}