为什么修饰符顺序会影响 Jetpack Compose 中宽高比的定位和大小?

问题描述 投票:0回答:1

实际上我正在阅读这个答案,但是没有足够的有关宽高比的信息。

矩形屏幕:

@Composable
fun RectangleScreen(modifier: Modifier) {
    Canvas(modifier.border(7.dp , color = Color.Red)) {
        drawRect(
            Color.Black
        )
    }
}

代码1:

setContent {
    RectangleScreen(modifier = Modifier
        .aspectRatio(1.0f)
        .border(7.dp , Color.Magenta)
        .fillMaxSize()
        .border(7.dp , Color.Yellow )
        .padding(64.dp)
        .border(7.dp , Color.Blue)
    )
}

在这种情况下,矩形屏幕会出现在屏幕顶部,呈正方形。

代码2:

setContent {
    RectangleScreen(modifier = Modifier
        .fillMaxSize()
        .border(7.dp , Color.Magenta)
        .aspectRatio(1.0f)
        .border(7.dp , Color.Yellow )
        .padding(64.dp)
        .border(7.dp , Color.Blue)
    )
}

在本例中,矩形屏幕也具有正方形形状,但它位于屏幕的中心。

我的理解

代码1:

因为在aspectRatio(1f)之前没有指定高度和宽度,并且默认情况下matchHeightConstraintsFirst: Boolean = false,所以它再次尝试通过传入约束来调整内容大小,首先检查Constraint.MaxWidth,然后检查Constraint.MaxHeight,然后检查minWidth,然后检查minHeight,所以没有约束是有效的,因此在末尾,约束将不会得到遵守,并且内容的大小将根据约束进行调整。最大宽度或约束。 maxHeight 已匹配(取决于 matchHeightConstraintsFirst)。 为什么我的顶部是正方形?

代码2:

由于高度和宽度在aspectRatio(1f)之前指定,并且默认情况下matchHeightConstraintsFirst: Boolean = false,因此它尝试通过尝试匹配传入约束之一来调整内容大小以匹配指定的宽高比1f,因此第一个约束是Constraint .MaxWidth 可以说是 1080.dp,这样可以保持宽高比,例如高度:宽度等于 1:1,所以我们的高度将为 1080.dp,这样我们就得到了正方形。 为什么方块的位置在屏幕中间

我的问题: 为什么代码 1 中屏幕顶部会出现正方形? 为什么代码 2 中的方块出现在屏幕中央? 这两种情况的大小和位置是如何计算的?

android android-jetpack-compose android-jetpack aspect-ratio
1个回答
0
投票

要了解为什么会发生这种情况,您需要了解 LayoutModifiers 和 Constraints 的工作原理。您可以查看这个答案了解更多详情。

尺寸和纵横比修改器获得合适的约束并用它进行测量,获得可放置的并放置它。

override fun MeasureScope.measure(
    measurable: Measurable,
    constraints: Constraints
): MeasureResult {
    val size = constraints.findSize()
    val wrappedConstraints = if (size != IntSize.Zero) {
        Constraints.fixed(size.width, size.height)
    } else {
        constraints
    }
    val placeable = measurable.measure(wrappedConstraints)
    return layout(placeable.width, placeable.height) {
        placeable.placeRelative(0, 0)
    }
}

aspectRatio 获得正确的宽度和高度后,它会设置

layout(placeable.width, placeable.height)
。如果此宽度和高度不遵守父级约束,则下一个修改器将以上一个或父级大小修改器为中心
Constraints

Modifier.fillMaxSize() 返回来自父约束的 minWidth=maxWidth 和 minHeight=maxHeight。

如果在这些约束之后将宽度和高度设置为另一个值,则下一个修饰符将居中。

如果您检查链接,我会解释 requiredSize,但在幕后,requiredSize、layout 或aspectRatio 可以做同样的事情,布局大小与父级的约束不匹配。

@Preview
@Composable
fun RequiredSizeTest() {
    RectangleScreen(
        modifier = Modifier
            .border(7.dp, Color.Red)
            .fillMaxSize()
            .border(7.dp, Color.Magenta)
            .requiredHeight(400.dp)
            .border(7.dp, Color.Yellow)
            .padding(64.dp)
            .border(7.dp, Color.Blue)
    )
}

结果

enter image description here

你也可以用

Modifier.layout
做同样的事情,下面的例子是aspectRatio在获得和高度后的表现

@Preview
@Composable
fun LayoutTest() {
    RectangleScreen(modifier = Modifier
        .border(7.dp, Color.Red)
        .fillMaxSize()
        .border(7.dp, Color.Magenta)
        .layout { measurable, constraints ->

            val width = constraints.maxWidth
            val height = width
            val wrappedConstraints = Constraints.fixed(width, height)
            val placeable = measurable.measure(wrappedConstraints)

            layout(placeable.width, placeable.height) {
                placeable.placeRelative(0, 0)
            }

        }
        .border(7.dp, Color.Yellow)
        .padding(64.dp)
        .border(7.dp, Color.Blue)
    )
}

enter image description here

您可以问为什么 Modifier.fillmaxSize/Width/Height 会发生这种情况,答案是,它将最小值和最大值限制为相同的值,比方说 minWidth=maxHeight 2000px,而宽度为 1000px,并且 1f 高度的宽高比变为 1000px好吧,所以它居中,因为 2000px 没有被遵守。

如果你没有设置 size Modifier,一般 Constraints 来自parent,除非你改变它, minHeight/minWidht =0 ,屏幕宽度和屏幕高度。由于这是一个间隔,父母的约束从aspectRatio修饰符中遵守1000px

© www.soinside.com 2019 - 2024. All rights reserved.