Can someone take a look at my code snippet and tel...
# compose-android
j
Can someone take a look at my code snippet and tell me if I’m doing this correctly? I want a
ScaleLayout {}
that will scale the content in
{}
to fit the max height available. What I have seems to work, but I just want to make sure i’m not doing something terribly wrong.
Copy code
@Composable
fun ScaledLayout(
    modifier: Modifier = Modifier,
    content: @Composable BoxWithConstraintsScope.() -> Unit,
) {
    BoxWithConstraints(modifier = modifier) {
        val constraints = this@BoxWithConstraints.constraints

        SubcomposeLayout { layoutConstraints ->
            val contentPlaceables = subcompose(slotId = "content") { content() }
                .map { measurable ->
                    val value = Constraints(
                        maxWidth = layoutConstraints.maxWidth,
                        maxHeight = Constraints.Infinity,
                    )
                    measurable.measure(value)
                }

            val contentHeight = contentPlaceables.maxOfOrNull { it.height }?.toFloat() ?: 0f
            val maxHeight = constraints.maxHeight.toFloat()

            val scale = if (contentHeight > 0) maxHeight / contentHeight else 1f

            val scaledWidth = ((contentPlaceables.maxOfOrNull { it.width } ?: (0 * scale))).toInt()
            val offsetX = (constraints.maxWidth - scaledWidth) / 2
            val offsetY = (constraints.maxHeight - contentHeight) / 2

            layout(constraints.maxWidth, constraints.maxHeight) {
                contentPlaceables.forEach { placeable ->
                    placeable.placeRelativeWithLayer(
                        offsetX,
                        offsetY.toInt()
                    ) {
                        scaleX = scale
                        scaleY = scale
                    }
                }
            }
        }
    }
}
a
This is extremely inefficient. You can do it with a single layout, instead of two subcompose layouts.
☝🏻 1
☝️ 2
j
Any code suggestions? I’m extremely new to the subcompose layout
a
Here's an example:
Copy code
@Composable
fun ScaledLayout(
    modifier: Modifier = Modifier,
    content: @Composable BoxScope.() -> Unit,
) {
    Layout(
        content = { Box(content = content) },
        modifier = modifier,
    ) { measurables, constraints ->
        val placeable = measurables.single()
            .measure(Constraints(maxWidth = constraints.maxWidth))
        val scale = if (placeable.height > 0) {
            constraints.maxHeight.toFloat() / placeable.height
        } else {
            1f
        }
        layout(constraints.maxWidth, constraints.maxHeight) {
            placeable.placeRelativeWithLayer(
                (constraints.maxWidth - placeable.width) / 2,
                (constraints.maxHeight - placeable.height) / 2,
            ) {
                scaleX = scale
                scaleY = scale
            }
        }
    }
}
SubcomposeLayout
(including
BoxWithConstraints
) is less performant than regular
Layout
so you should avoid it when possible. Basically you only need
SubcomposeLayout
if: • You need the incoming constraints (layout size etc.) when you compose the children • You need the measured size of some other children when you compose the children • You need the incoming constraints and/or the measured size of some other children to decide whether to compose some children You don't need
SubcomposeLayout
if you need the incoming constraints and/or the measured size of some other children when you measure and layout the children.
j
That’s really helpful! Thank you very much 🙌