自定义布局忽略Composeable的大小

3

我目前正在尝试使用Jetpack Compose中的自定义布局。这只是为了测试而已,这是我得到的结果:

@Preview(widthDp = 1000, heightDp = 1000)
@Composable
fun MyLayout() {
    Layout({ Box(Modifier.size(48.dp).background(Color.Blue)) }) { measurables, constraints ->
        val placeables = measurables.map { it.measure(constraints) }
        layout(constraints.maxWidth, constraints.maxHeight) {
            placeables.forEach { it.place(0, 0) }
        }
    }
}

我的问题是Box填充了整个布局而不仅仅是48.dp的大小。有人能解释一下为什么吗?我在这里阅读了有关创建自定义布局的内容,但没有找到任何有用的信息。

2个回答

4

Layout 的大小由传递到 layout(width, height) 中的大小决定。

你的 Layout 没有任何修饰符,这就是为什么它的 maxWidth/maxHeight 约束等于可用空间。使用 layout(constraints.maxWidth, constraints.maxHeight) 具有与应用 Modifier.fillMaxSize 相同的效果。实际上,使用 Modifier.fillMaxSize 会将最大和最小约束都设置为可用大小。

要解决此问题,你有两个选项:

  1. Apply Modifier.size to the Layout itself, instead of applying to the Box - in this case max/min constraints will be 48.dp

  2. Calculate layout size depending on placeable. The actual code depend on what layout do you expect to get. Your code looks like Box analog, so you need maximum of all placeable sizes:

    layout(placeables.maxOfOrNull { it.width } ?: 0, placeables.maxOfOrNull { it.height } ?: 0) {
    

谢谢,我尝试了你的第二种方法,但它没有起作用。我在布局中添加了两个框,一个使用48.dp,另一个使用96.dp,尝试将它们都放置在(0,0),但是它们占用了相同的空间。现在我只想要类似于FrameLayout的东西,其中元素可以堆叠在一起。 - Cilenco
@Cilenco 不确定你尝试了什么。这段代码对我来说产生了这个输出,我认为这是预期的。 - Phil Dukhov
1
你说得对,是我的错。我在方法上使用了@Preview(widthDp = 1000, heightDp = 1000)。删除widthDpheightDp后,它正确地显示了。我还在我的手机上测试了一下,也可以正常显示。对此我感到很抱歉! - Cilenco

0
之所以蓝色框填满整个布局,是由于以下几个原因的结合:(1)您为@ Preview注释指定了尺寸,(2)您未修改Layout的约束条件来测量该框,(3)使用size修饰符。
因为第1点,Layout的约束条件将同时设置最小值和最大值,以符合Preview尺寸的指定值。因为第2点,这些严格的最小值和最大值用于测量框。因为第3点,传入的约束条件优先于所请求的大小(这就是size修饰符的工作方式)。
解决每个问题将解决您的问题。
正如您已经从其他答案中发现的那样,从预览注释中删除宽度和高度将使其看起来正确。这是因为如果没有在预览注释中指定宽度和高度,则约束将具有最小值为0,因此现在可以允许子可测量对象采取其所需的大小。

推荐的方法是解决第二个问题:在将约束传递给可测量对象的测量方法之前,更改约束以适应自定义布局的要求。在这种情况下,您可能需要创建约束的副本,并将最小宽度和高度设置为0。

最后,您可以通过使用requiredSize来解决第三个问题,这将使可测量对象的大小始终符合所需大小,即使它仍然会向其父级通信一个在约束范围内的大小。通常不建议在生产代码中使用此方法,因为它使大小绝对化,但对于预览来说应该没问题,甚至对于测试也可能是可取的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接