Reputation: 33
I'm trying to implement a Custom "Row" Layout in Android compose like this:
@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
}
}
}
}
Here is the preview for this composable:
@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)) {
}
}
}
The issue here is that each measurable
(Box), after being measured, got parent width, hence, 1080dp, and not the desired width passed to the boxes which caused the first child to take all space.
see: Preview
What is expected to be in theory: (Box 32dp)(Box 100dp)(Box 32dp)
What I'm missing here?
I tried the documentation, but I could not understand a way to achieve something like plain android Custom ViewGroup.onMeasure
like :
view.measure(MeasureSpec.makeMeasureSpec(wantedSize, AT_MOST or EXACT))
, where wantedSize
can be fetched from LayoutParams or from the WRAP_CONTENT
strategy.
Environment: Android Studio Arctic Fox. Compose: 1.0.0. Kotlin: 1.5.10. AGP and Gradle: 7.0.0.
Upvotes: 3
Views: 2343
Reputation: 29330
You have to make a copy of your constraints and change the min to 0. Change it like this:
@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
}
}
}
}
Upvotes: 9
Reputation: 6863
Ok you should not use placeable.measuredWidth
over there. Just replace it with placeable.width
. Also, in your mapping logic, you don't at all need that val
. Just do this
val placeables = measurables.map {
it.measure(constraints)
}
Visit here to learn more
Upvotes: -1