by @alexstyl
✉️ Leave your feedback

← Back to Compose UI

Layout

Component
in
Compose UI
. Since 0.1.0-dev15

Overview

Examples

Community Notes

Video

@Composable
fun LayoutUsage(content: @Composable () -> Unit) {
    // We build a layout that will occupy twice as much space as its children,
    // and will position them to be bottom right aligned.
    Layout(content) { measurables, constraints ->
        // measurables contains one element corresponding to each of our layout children.
        // constraints are the constraints that our parent is currently measuring us with.
        val childConstraints = Constraints(
            minWidth = constraints.minWidth / 2,
            minHeight = constraints.minHeight / 2,
            maxWidth = if (constraints.hasBoundedWidth) {
                constraints.maxWidth / 2
            } else {
                Constraints.Infinity
            },
            maxHeight = if (constraints.hasBoundedHeight) {
                constraints.maxHeight / 2
            } else {
                Constraints.Infinity
            }
        )
        // We measure the children with half our constraints, to ensure we can be double
        // the size of the children.
        val placeables = measurables.map { it.measure(childConstraints) }
        val layoutWidth = (placeables.maxByOrNull { it.width }?.width ?: 0) * 2
        val layoutHeight = (placeables.maxByOrNull { it.height }?.height ?: 0) * 2
        // We call layout to set the size of the current layout and to provide the positioning
        // of the children. The children are placed relative to the current layout place.
        layout(layoutWidth, layoutHeight) {
            placeables.forEach {
                it.placeRelative(layoutWidth - it.width, layoutHeight - it.height)
            }
        }
    }
}
@Composable
fun LayoutWithProvidedIntrinsicsUsage(content: @Composable () -> Unit) {
    // We build a layout that will occupy twice as much space as its children,
    // and will position them to be bottom right aligned.
    val measurePolicy = object : MeasurePolicy {
        override fun MeasureScope.measure(
            measurables: List<Measurable>,
            constraints: Constraints
        ): MeasureResult {
            // measurables contains one element corresponding to each of our layout children.
            // constraints are the constraints that our parent is currently measuring us with.
            val childConstraints = Constraints(
                minWidth = constraints.minWidth / 2,
                minHeight = constraints.minHeight / 2,
                maxWidth = if (constraints.hasBoundedWidth) {
                    constraints.maxWidth / 2
                } else {
                    Constraints.Infinity
                },
                maxHeight = if (constraints.hasBoundedHeight) {
                    constraints.maxHeight / 2
                } else {
                    Constraints.Infinity
                }
            )
            // We measure the children with half our constraints, to ensure we can be double
            // the size of the children.
            val placeables = measurables.map { it.measure(childConstraints) }
            val layoutWidth = (placeables.maxByOrNull { it.width }?.width ?: 0) * 2
            val layoutHeight = (placeables.maxByOrNull { it.height }?.height ?: 0) * 2
            // We call layout to set the size of the current layout and to provide the positioning
            // of the children. The children are placed relative to the current layout place.
            return layout(layoutWidth, layoutHeight) {
                placeables.forEach {
                    it.placeRelative(layoutWidth - it.width, layoutHeight - it.height)
                }
            }
        }

        // The min intrinsic width of this layout will be twice the largest min intrinsic
        // width of a child. Note that we call minIntrinsicWidth with h / 2 for children,
        // since we should be double the size of the children.
        override fun IntrinsicMeasureScope.minIntrinsicWidth(
            measurables: List<IntrinsicMeasurable>,
            height: Int
        ) = (measurables.map { it.minIntrinsicWidth(height / 2) }.maxByOrNull { it } ?: 0) * 2

        override fun IntrinsicMeasureScope.minIntrinsicHeight(
            measurables: List<IntrinsicMeasurable>,
            width: Int
        ) = (measurables.map { it.minIntrinsicHeight(width / 2) }.maxByOrNull { it } ?: 0) * 2

        override fun IntrinsicMeasureScope.maxIntrinsicWidth(
            measurables: List<IntrinsicMeasurable>,
            height: Int
        ) = (measurables.map { it.maxIntrinsicHeight(height / 2) }.maxByOrNull { it } ?: 0) * 2

        override fun IntrinsicMeasureScope.maxIntrinsicHeight(
            measurables: List<IntrinsicMeasurable>,
            width: Int
        ) = (measurables.map { it.maxIntrinsicHeight(width / 2) }.maxByOrNull { it } ?: 0) * 2
    }

    Layout(content = content, measurePolicy = measurePolicy)
}

@Composable
fun LayoutUsage(content: @Composable () -> Unit) {
    // We build a layout that will occupy twice as much space as its children,
    // and will position them to be bottom right aligned.
    Layout(content) { measurables, constraints ->
        // measurables contains one element corresponding to each of our layout children.
        // constraints are the constraints that our parent is currently measuring us with.
        val childConstraints = Constraints(
            minWidth = constraints.minWidth / 2,
            minHeight = constraints.minHeight / 2,
            maxWidth = if (constraints.hasBoundedWidth) {
                constraints.maxWidth / 2
            } else {
                Constraints.Infinity
            },
            maxHeight = if (constraints.hasBoundedHeight) {
                constraints.maxHeight / 2
            } else {
                Constraints.Infinity
            }
        )
        // We measure the children with half our constraints, to ensure we can be double
        // the size of the children.
        val placeables = measurables.map { it.measure(childConstraints) }
        val layoutWidth = (placeables.maxByOrNull { it.width }?.width ?: 0) * 2
        val layoutHeight = (placeables.maxByOrNull { it.height }?.height ?: 0) * 2
        // We call layout to set the size of the current layout and to provide the positioning
        // of the children. The children are placed relative to the current layout place.
        layout(layoutWidth, layoutHeight) {
            placeables.forEach {
                it.placeRelative(layoutWidth - it.width, layoutHeight - it.height)
            }
        }
    }
}
@Composable
fun LayoutWithProvidedIntrinsicsUsage(content: @Composable () -> Unit) {
    // We build a layout that will occupy twice as much space as its children,
    // and will position them to be bottom right aligned.
    val measurePolicy = object : MeasurePolicy {
        override fun MeasureScope.measure(
            measurables: List<Measurable>,
            constraints: Constraints
        ): MeasureResult {
            // measurables contains one element corresponding to each of our layout children.
            // constraints are the constraints that our parent is currently measuring us with.
            val childConstraints = Constraints(
                minWidth = constraints.minWidth / 2,
                minHeight = constraints.minHeight / 2,
                maxWidth = if (constraints.hasBoundedWidth) {
                    constraints.maxWidth / 2
                } else {
                    Constraints.Infinity
                },
                maxHeight = if (constraints.hasBoundedHeight) {
                    constraints.maxHeight / 2
                } else {
                    Constraints.Infinity
                }
            )
            // We measure the children with half our constraints, to ensure we can be double
            // the size of the children.
            val placeables = measurables.map { it.measure(childConstraints) }
            val layoutWidth = (placeables.maxByOrNull { it.width }?.width ?: 0) * 2
            val layoutHeight = (placeables.maxByOrNull { it.height }?.height ?: 0) * 2
            // We call layout to set the size of the current layout and to provide the positioning
            // of the children. The children are placed relative to the current layout place.
            return layout(layoutWidth, layoutHeight) {
                placeables.forEach {
                    it.placeRelative(layoutWidth - it.width, layoutHeight - it.height)
                }
            }
        }

        // The min intrinsic width of this layout will be twice the largest min intrinsic
        // width of a child. Note that we call minIntrinsicWidth with h / 2 for children,
        // since we should be double the size of the children.
        override fun IntrinsicMeasureScope.minIntrinsicWidth(
            measurables: List<IntrinsicMeasurable>,
            height: Int
        ) = (measurables.map { it.minIntrinsicWidth(height / 2) }.maxByOrNull { it } ?: 0) * 2

        override fun IntrinsicMeasureScope.minIntrinsicHeight(
            measurables: List<IntrinsicMeasurable>,
            width: Int
        ) = (measurables.map { it.minIntrinsicHeight(width / 2) }.maxByOrNull { it } ?: 0) * 2

        override fun IntrinsicMeasureScope.maxIntrinsicWidth(
            measurables: List<IntrinsicMeasurable>,
            height: Int
        ) = (measurables.map { it.maxIntrinsicHeight(height / 2) }.maxByOrNull { it } ?: 0) * 2

        override fun IntrinsicMeasureScope.maxIntrinsicHeight(
            measurables: List<IntrinsicMeasurable>,
            width: Int
        ) = (measurables.map { it.maxIntrinsicHeight(width / 2) }.maxByOrNull { it } ?: 0) * 2
    }

    Layout(content = content, measurePolicy = measurePolicy)
}

@Composable
fun LayoutWithMultipleContentsUsage(
    content1: @Composable () -> Unit,
    content2: @Composable () -> Unit,
) {
    // We can provide pass a list of two composable lambdas in order to be able to treat
    // measureables from each lambda differently.
    Layout(listOf(content1, content2)) { (content1Measurables, content2Measurables), constraints ->
        val content1Placeables = content1Measurables.map { it.measure(constraints) }
        val content2Placeables = content2Measurables.map { it.measure(constraints) }
        layout(constraints.maxWidth, constraints.maxHeight) {
            var currentX = 0
            var currentY = 0
            var currentMaxHeight = 0
            // we place placeables from content1 as a first line
            content1Placeables.forEach {
                it.place(currentX, currentY)
                currentX += it.width
                currentMaxHeight = maxOf(currentMaxHeight, it.height)
            }
            currentX = 0
            currentY = currentMaxHeight
            // and placeables from content2 composable as a second line
            content2Placeables.forEach {
                it.place(currentX, currentY)
                currentX += it.width
            }
        }
    }
}
Previous ComponentGroup
Next ComponentLookaheadLayout