Reputation: 7179
I'm currently playing around with custom Layouts in Jetpack Compose. This is what i got so far just for testing:
@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) }
}
}
}
My problem here is that the Box
fills the whole layout and not only it's size of 48.dp
. Can someone explain to me why this is? I read here about creating custom layouts but couldn't find anything usefull.
Upvotes: 3
Views: 1920
Reputation: 1946
The reason why the blue box fills the entire Layout
is because of a combination of a few things: (1) you specify dimensions for the @Preview
annotation, (2) you use the Layout
's constraints unmodified to measure the box, and (3) the use of the size
modifier.
Because of point 1, the constraints of the Layout
will have both the minimum and maximum set to what was specified in the Preview dimensions. Because of point 2 those strict minimums and maximums are used to measure the box. And because of point 3 the incoming constraints take priority over the requested size (that's the way the size
modifier works).
Mitigating each of those points will solve your problem.
As you already found out from one of the other answers, removing the width and height from the preview annotation will make those seem right. That is because without the width and height specified in the Preview annotation, the constraints will have a minimum of 0, so the child measurable are now allowed to take the size they want.
The recommended way though is to fix point 2: change the constraints to fit the requirements of your custom layout before you pass them to the measurables' measure methods. In this case, you probably want to create a copy of the constraints and set the minimum width and height to 0.
And finally you can fix point 3 by using requiredSize
instead, which will size the measurable to the required size regardless, even though it will still communicate to its parents a size that's within the constraints. This is usually not recommended in production code because it makes sizing absolute, but for a preview it should be fine, and for tests it could even be desirable.
Upvotes: 0
Reputation: 88222
Layout
size is determined by the size passed into layout(width, height)
.
Your Layout
doesn't have any modifiers, that's why it has maxWidth
/maxHeight
constraints equal to available spacing. Using layout(constraints.maxWidth, constraints.maxHeight)
has the same effect as applying Modifier.fillMaxSize
. Actually with Modifier.fillMaxSize
your'll set both max and min constraints to the available size.
To solve this you have two options:
Apply Modifier.size
to the Layout
itself, instead of applying to the Box
- in this case max/min constraints will be 48.dp
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) {
Upvotes: 4