{% setvar book_path %}/reference/kotlin/androidx/_book.yaml{% endsetvar %} {% include "_shared/_reference-head-tags.html" %}

androidx.compose.ui.layout

Interfaces

BeyondBoundsLayout

Layout extra items in the specified direction.

Cmn
BeyondBoundsLayout.BeyondBoundsScope

The scope used in BeyondBoundsLayout.layout.

Cmn
ContentScale

Represents a rule to apply to scale a source rectangle to be inscribed into a destination

Cmn
GraphicLayerInfo

The info about the graphics layers used by tooling.

android
IntermediateMeasureScope

IntermediateMeasureScope provides access to lookahead results to allow intermediateLayout to leverage lookahead results to define intermediate measurements and placements to gradually converge with lookahead.

Cmn
IntrinsicMeasurable

A part of the composition that can be measured.

Cmn
IntrinsicMeasureScope

The receiver scope of a layout's intrinsic measurements lambdas.

Cmn
LayoutCoordinates

A holder of the measured bounds for the Layout.

Cmn
LayoutIdParentData

Can be implemented by values used as parent data to make them usable as tags.

Cmn
LayoutInfo

The public information about the layouts used internally as nodes in the Compose UI hierarchy.

Cmn
LayoutModifier

A Modifier.Element that changes how its wrapped content is measured and laid out.

Cmn
LookaheadLayoutCoordinates

This interface is deprecated. LookaheadLayoutCoordinates class has been removed. localLookaheadPositionOfcan be achieved in LookaheadScope using LayoutCoordinates.localLookaheadPositionOf(LayoutCoordinates) function.

Cmn
LookaheadLayoutScope

This interface is deprecated. LookaheadLayoutScope has been renamed to LookaheadScope

Cmn
LookaheadScope

LookaheadScope provides a receiver scope for all (direct and indirect) child layouts in LookaheadScope.

Cmn
Measurable

A part of the composition that can be measured.

Cmn
MeasurePolicy

Defines the measure and layout behavior of a Layout.

Cmn
MeasureResult

Interface holding the size and alignment lines of the measured layout, as well as the children positioning logic.

Cmn
MeasureScope

The receiver scope of a layout's measure lambda.

Cmn
Measured

A Measured corresponds to a layout that has been measured by its parent layout.

Cmn
MultiContentMeasurePolicy

Defines the measure and layout behavior of a Layout overload which accepts a list of multiple composable content lambdas.

Cmn
OnGloballyPositionedModifier

A modifier whose onGloballyPositioned is called with the final LayoutCoordinates of the Layout when the global position of the content may have changed.

Cmn
OnPlacedModifier

A modifier whose onPlaced is called after the parent LayoutModifier and parent layout has been placed and before child LayoutModifier is placed.

Cmn
OnRemeasuredModifier

A modifier whose onRemeasured is called when the layout content is remeasured.

Cmn
ParentDataModifier

A Modifier that provides data to the parent Layout.

Cmn
PinnableContainer

Represents a container which can be pinned when the content of this container is important.

Cmn
PinnableContainer.PinnedHandle

This is an object returned by pin which allows to release the pinning.

Cmn
RelocationModifier

This interface is deprecated. Please use BringIntoViewResponder instead.

Cmn
Remeasurement

This object is associated with a layout node and allows to execute some extra measure/layout actions which are needed for some complex layouts.

Cmn
RemeasurementModifier

A Modifier.Element that provides a Remeasurement object associated with the layout node the modifier is applied to.

Cmn
SubcomposeIntermediateMeasureScope

SubcomposeIntermediateMeasureScope is the receiver scope for the intermediate measurer policy that gets invoked during the intermediate measure pass.

Cmn
SubcomposeLayoutState.PrecomposedSlotHandle

Instance of this interface is returned by precompose function.

Cmn
SubcomposeMeasureScope

The receiver scope of a SubcomposeLayout's measure lambda which adds ability to dynamically subcompose a content during the measuring on top of the features provided by MeasureScope.

Cmn
SubcomposeSlotReusePolicy

This policy allows SubcomposeLayout to retain some of slots which we were used but not used anymore instead of disposing them.

Cmn

Classes

AlignmentLine

Defines an offset line that can be used by parent layouts to align and position their children.

Cmn
BeyondBoundsLayout.LayoutDirection

The direction (from the visible bounds) that a BeyondBoundsLayout is requesting more items to be laid.

Cmn
FixedScale

ContentScale implementation that always scales the dimension by the provided fixed floating point value

Cmn
HorizontalAlignmentLine

A horizontal AlignmentLine.

Cmn
ModifierInfo

Used by tooling to examine the modifiers on a LayoutInfo.

Cmn
Placeable

A Placeable corresponds to a child layout that can be positioned by its parent layout.

Cmn
Placeable.PlacementScope

Receiver scope that permits explicit placement of a Placeable.

Cmn
RelocationRequester

This class is deprecated. Please use BringIntoViewRequester instead.

Cmn
ScaleFactor

Holds 2 dimensional scaling factors for horizontal and vertical axes

Cmn
SubcomposeLayoutState

State used by SubcomposeLayout.

Cmn
SubcomposeSlotReusePolicy.SlotIdsSet

Set containing slot ids currently available to reuse.

Cmn
VerticalAlignmentLine

A vertical AlignmentLine.

Cmn

Top-level functions summary

inline Unit
@Composable
@UiComposable
Layout(modifier: Modifier, measurePolicy: MeasurePolicy)

Layout is the main core component for layout for "leaf" nodes.

Cmn
inline Unit
@UiComposable
@Composable
Layout(
    content: @Composable @UiComposable () -> Unit,
    modifier: Modifier,
    measurePolicy: MeasurePolicy
)

Layout is the main core component for layout.

Cmn
inline Unit
@UiComposable
@Composable
Layout(
    contents: List<@Composable @UiComposable () -> Unit>,
    modifier: Modifier,
    measurePolicy: MultiContentMeasurePolicy
)

Layout is the main core component for layout.

Cmn
Unit

This function is deprecated. LookaheadLayout has been replaced with LookaheadScope that does not require a Modifier or a MeasurePolicy.

Cmn
Unit

LookaheadScope starts a scope in which all layouts scope will receive a lookahead pass preceding the main measure/layout pass.

Cmn
Unit
@Composable
@UiComposable
MultiMeasureLayout(
    modifier: Modifier,
    content: @Composable @UiComposable () -> Unit,
    measurePolicy: MeasurePolicy
)

This function is deprecated. This API is unsafe for UI performance at scale - using it incorrectly will lead to exponential performance issues.

Cmn
ScaleFactor
ScaleFactor(scaleX: Float, scaleY: Float)

Constructs a ScaleFactor from the given x and y scale values

Cmn
Unit
@Composable
SubcomposeLayout(
    modifier: Modifier,
    measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult
)

Analogue of Layout which allows to subcompose the actual content during the measuring stage for example to use the values calculated during the measurement as params for the composition of the children.

Cmn
Unit

Analogue of Layout which allows to subcompose the actual content during the measuring stage for example to use the values calculated during the measurement as params for the composition of the children.

Cmn
Unit

Analogue of Layout which allows to subcompose the actual content during the measuring stage for example to use the values calculated during the measurement as params for the composition of the children.

Cmn
Unit

Analogue of Layout which allows to subcompose the actual content during the measuring stage for example to use the values calculated during the measurement as params for the composition of the children.

Cmn
SubcomposeSlotReusePolicy
SubcomposeSlotReusePolicy(maxSlotsToRetainForReuse: Int)

Creates SubcomposeSlotReusePolicy which retains the fixed amount of slots.

Cmn
ScaleFactor
lerp(start: ScaleFactor, stop: ScaleFactor, fraction: Float)

Linearly interpolate between two ScaleFactor parameters

Cmn

Extension functions summary

Rect

Returns the bounding box of the child in the parent's content area, including any clipping done with respect to the parent.

Cmn
Rect

The boundaries of this layout inside the root composable.

Cmn
Rect

The boundaries of this layout relative to the window's origin.

Cmn
operator Size
Size.div(scaleFactor: ScaleFactor)

Division operator with Size

Cmn
LayoutCoordinates

Walks up the LayoutCoordinates hierarchy to find the LayoutCoordinates whose LayoutCoordinates.parentCoordinates is null and returns it.

Cmn
Modifier

Creates an intermediate layout intended to help morph the layout from the current layout to the lookahead (i.e. pre-calculated future) layout.

Cmn
Modifier

Creates a LayoutModifier that allows changing how the wrapped element is measured and laid out.

Cmn
Modifier
Modifier.layoutId(layoutId: Any)

Tag the element with layoutId to identify the element within its parent.

Cmn
Modifier
Modifier.onGloballyPositioned(
    onGloballyPositioned: (LayoutCoordinates) -> Unit
)

Invoke onGloballyPositioned with the LayoutCoordinates of the element when the global position of the content may have changed.

Cmn
Modifier

Invoke onPlaced after the parent LayoutModifier and parent layout has been placed and before child LayoutModifier is placed.

Cmn
Modifier
@ExperimentalComposeUiApi
Modifier.onRelocationRequest(
    onProvideDestination: (rect: Rect, layoutCoordinates: LayoutCoordinates) -> Rect,
    onPerformRelocation: suspend (sourceRect: Rect, destinationRect: Rect) -> Unit
)

This function is deprecated. Please use BringIntoViewResponder instead.

Cmn
Modifier
Modifier.onSizeChanged(onSizeChanged: (IntSize) -> Unit)

Invoked with the size of the modified Compose UI element when the element is first measured or when the size of the element changes.

Cmn
Offset

Returns the position of the top-left in the parent's content area or (0, 0) for the root.

Cmn
Offset

The position of this layout inside the root composable.

Cmn
Offset

The position of this layout relative to the window.

Cmn
Modifier

This function is deprecated. Please use bringIntoViewRequester instead.

Cmn
inline ScaleFactor

If this ScaleFactor then this is returned, otherwise block is executed and its result is returned.

Cmn
operator Size
Size.times(scaleFactor: ScaleFactor)

Multiplication operator with Size.

Cmn
operator Size

Multiplication operator with Size with reverse parameter types to maintain commutative properties of multiplication

Cmn

Top-level properties summary

HorizontalAlignmentLine

AlignmentLine defined by the baseline of a first line of a androidx.foundation.text.CoreText

Cmn
HorizontalAlignmentLine

AlignmentLine defined by the baseline of the last line of a androidx.foundation.text.CoreText

Cmn
ProvidableCompositionLocal<PinnableContainer?>

Use this composition local to get the PinnableContainer handling the current subhierarchy.

Cmn
ProvidableModifierLocal<BeyondBoundsLayout?>

A modifier local that provides access to a BeyondBoundsLayout that a child can use to ask a parent to layout more items that are beyond its visible bounds.

Cmn

Extension properties summary

Boolean

false when this is ScaleFactor.Unspecified.

Cmn
Boolean

true when this is ScaleFactor.Unspecified.

Cmn
Any?

Retrieves the tag associated to a composable with the Modifier.layoutId modifier.

Cmn

Top-level functions

Layout

@Composable
@UiComposable
inline fun Layout(modifier: Modifier = Modifier, measurePolicy: MeasurePolicy): Unit

Layout is the main core component for layout for "leaf" nodes. It can be used to measure and position zero children.

The measurement, layout and intrinsic measurement behaviours of this layout will be defined by the measurePolicy instance. See MeasurePolicy for more details.

For a composable able to define its content according to the incoming constraints, see androidx.compose.foundation.layout.BoxWithConstraints.

Example usage:

import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Constraints

// 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)
        }
    }
}

Example usage with custom intrinsic measurements:

import androidx.compose.ui.layout.IntrinsicMeasurable
import androidx.compose.ui.layout.IntrinsicMeasureScope
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasurePolicy
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Constraints

// 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)
Parameters
modifier: Modifier = Modifier

Modifiers to be applied to the layout.

measurePolicy: MeasurePolicy

The policy defining the measurement and positioning of the layout.

See also
Layout
MeasurePolicy
BoxWithConstraints

Layout

@UiComposable
@Composable
inline fun Layout(
    content: @Composable @UiComposable () -> Unit,
    modifier: Modifier = Modifier,
    measurePolicy: MeasurePolicy
): Unit

Layout is the main core component for layout. It can be used to measure and position zero or more layout children.

The measurement, layout and intrinsic measurement behaviours of this layout will be defined by the measurePolicy instance. See MeasurePolicy for more details.

For a composable able to define its content according to the incoming constraints, see androidx.compose.foundation.layout.BoxWithConstraints.

Example usage:

import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Constraints

// 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)
        }
    }
}

Example usage with custom intrinsic measurements:

import androidx.compose.ui.layout.IntrinsicMeasurable
import androidx.compose.ui.layout.IntrinsicMeasureScope
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasurePolicy
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.MeasureScope
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Constraints

// 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)
Parameters
content: @Composable @UiComposable () -> Unit

The children composable to be laid out.

modifier: Modifier = Modifier

Modifiers to be applied to the layout.

measurePolicy: MeasurePolicy

The policy defining the measurement and positioning of the layout.

See also
Layout
MeasurePolicy
BoxWithConstraints

Layout

@UiComposable
@Composable
inline fun Layout(
    contents: List<@Composable @UiComposable () -> Unit>,
    modifier: Modifier = Modifier,
    measurePolicy: MultiContentMeasurePolicy
): Unit

Layout is the main core component for layout. It can be used to measure and position zero or more layout children.

This overload accepts a list of multiple composable content lambdas, which allows treating measurables put into different content lambdas differently - measure policy will provide a list of lists of Measurables, not just a single list. Such list has the same size as the list of contents passed into Layout and contains the list of measurables of the corresponding content lambda in the same order.

Note that layouts emitted as part of all contents lambdas will be added as a direct children for this Layout. This means that if you set a custom z index on some children, the drawing order will be calculated as if they were all provided as part of one lambda.

Example usage:

import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.layout

// 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
        }
    }
}
Parameters
contents: List<@Composable @UiComposable () -> Unit>

The list of children composable contents to be laid out.

modifier: Modifier = Modifier

Modifiers to be applied to the layout.

measurePolicy: MultiContentMeasurePolicy

The policy defining the measurement and positioning of the layout.

See also
Layout

for a simpler use case when you have only one content lambda.

LookaheadLayout

@ExperimentalComposeUiApi
@UiComposable
@Composable
fun LookaheadLayout(
    content: @Composable @UiComposable LookaheadScope.() -> Unit,
    modifier: Modifier = Modifier,
    measurePolicy: MeasurePolicy
): Unit

LookaheadScope

@ExperimentalComposeUiApi
@UiComposable
@Composable
fun LookaheadScope(content: @Composable @UiComposable LookaheadScope.() -> Unit): Unit

LookaheadScope starts a scope in which all layouts scope will receive a lookahead pass preceding the main measure/layout pass. This lookahead pass will calculate the layout size and position for all child layouts, and make the lookahead results available in Modifier.intermediateLayout. Modifier.intermediateLayout gets invoked in the main pass to allow transient layout changes in the main pass that gradually morph the layout over the course of multiple frames until it catches up with lookahead.

import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector2D
import androidx.compose.animation.core.VectorConverter
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.getValue
import androidx.compose.runtime.movableContentOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.LookaheadScope
import androidx.compose.ui.layout.intermediateLayout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.round

// Creates a custom modifier to animate the local position of the layout within the
// given LookaheadScope, whenever the relative position changes.
fun Modifier.animatePlacementInScope(lookaheadScope: LookaheadScope) = composed {
    // Creates an offset animation
    var offsetAnimation: Animatable<IntOffset, AnimationVector2D>? by mutableStateOf(
        null
    )
    var targetOffset: IntOffset? by mutableStateOf(null)

    this.intermediateLayout { measurable, constraints ->
        val placeable = measurable.measure(constraints)
        layout(placeable.width, placeable.height) {
            // Converts coordinates of the current layout to LookaheadCoordinates
            val coordinates = coordinates
            if (coordinates != null) {
                // Calculates the target offset within the lookaheadScope
                val target = with(lookaheadScope) {
                    lookaheadScopeCoordinates
                        .localLookaheadPositionOf(coordinates)
                        .round().also { targetOffset = it }
                }

                // Uses the target offset to start an offset animation
                if (target != offsetAnimation?.targetValue) {
                    offsetAnimation?.run {
                        launch { animateTo(target) }
                    } ?: Animatable(target, IntOffset.VectorConverter).let {
                        offsetAnimation = it
                    }
                }
                // Calculates the *current* offset within the given LookaheadScope
                val placementOffset =
                    lookaheadScopeCoordinates.localPositionOf(
                        coordinates,
                        Offset.Zero
                    ).round()
                // Calculates the delta between animated position in scope and current
                // position in scope, and places the child at the delta offset. This puts
                // the child layout at the animated position.
                val (x, y) = requireNotNull(offsetAnimation).run { value - placementOffset }
                placeable.place(x, y)
            } else {
                placeable.place(0, 0)
            }
        }
    }
}

val colors = listOf(
    Color(0xffff6f69), Color(0xffffcc5c), Color(0xff264653), Color(0xff2a9d84)
)

var isInColumn by remember { mutableStateOf(true) }
LookaheadScope {
    // Creates movable content containing 4 boxes. They will be put either in a [Row] or in a
    // [Column] depending on the state
    val items = remember {
        movableContentOf {
            colors.forEach { color ->
                Box(
                    Modifier
                        .padding(15.dp)
                        .size(100.dp, 80.dp)
                        .animatePlacementInScope(this)
                        .background(color, RoundedCornerShape(20))
                )
            }
        }
    }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .clickable { isInColumn = !isInColumn }
    ) {
        // As the items get moved between Column and Row, their positions in LookaheadLayout
        // will change. The `animatePlacementInScope` modifier created above will
        // observe that final position change via `localLookaheadPositionOf`, and create
        // a position animation.
        if (isInColumn) {
            Column(Modifier.fillMaxSize()) {
                items()
            }
        } else {
            Row { items() }
        }
    }
}
Parameters
content: @Composable @UiComposable LookaheadScope.() -> Unit

The child composable to be laid out.

MultiMeasureLayout

@Composable
@UiComposable
fun MultiMeasureLayout(
    modifier: Modifier = Modifier,
    content: @Composable @UiComposable () -> Unit,
    measurePolicy: MeasurePolicy
): Unit

ScaleFactor

fun ScaleFactor(scaleX: Float, scaleY: Float): ScaleFactor

Constructs a ScaleFactor from the given x and y scale values

SubcomposeLayout

@Composable
fun SubcomposeLayout(
    modifier: Modifier = Modifier,
    measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult
): Unit

Analogue of Layout which allows to subcompose the actual content during the measuring stage for example to use the values calculated during the measurement as params for the composition of the children.

Possible use cases:

import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.unit.IntSize

// enum class SlotsEnum { Main, Dependent }
SubcomposeLayout { constraints ->
    val mainPlaceables = subcompose(SlotsEnum.Main, mainContent).map {
        it.measure(constraints)
    }
    val maxSize = mainPlaceables.fold(IntSize.Zero) { currentMax, placeable ->
        IntSize(
            width = maxOf(currentMax.width, placeable.width),
            height = maxOf(currentMax.height, placeable.height)
        )
    }
    layout(maxSize.width, maxSize.height) {
        mainPlaceables.forEach { it.placeRelative(0, 0) }
        subcompose(SlotsEnum.Dependent) {
            dependentContent(maxSize)
        }.forEach {
            it.measure(constraints).placeRelative(0, 0)
        }
    }
}
Parameters
modifier: Modifier = Modifier

Modifier to apply for the layout.

measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult

Measure policy which provides ability to subcompose during the measuring.

SubcomposeLayout

@ExperimentalComposeUiApi
@Composable
fun SubcomposeLayout(
    modifier: Modifier = Modifier,
    intermediateMeasurePolicy: SubcomposeIntermediateMeasureScope.(Constraints) -> MeasureResult = { constraints -> lookaheadMeasurePolicy(constraints) },
    measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult
): Unit

Analogue of Layout which allows to subcompose the actual content during the measuring stage for example to use the values calculated during the measurement as params for the composition of the children.

When in a LookaheadScope, SubcomposeLayout will be measured up to twice per frame. The two measurements will be using different measure policies and potentially different constraints.

The first measurement happens in the lookahead pass, where new layout is calculated based on the target constraints. Therefore, measurePolicy will receive the target constraints, and subcompose its content based on the target constraints. Note: Target constraints refers to the constraints that the SubcomposeLayout will receive once all the lookahead-based animations on size/constraints in the ancestor layouts have finished.

The second measurement is done in the intermediate measure pass after the lookahead pass. The intermediate measure pass allows adjustments to the measurement/placement using the pre-calculated layout information as animation targets to smooth over any any layout changes. In this measurement, intermediateMeasurePolicy will be invoked with the intermediate/animating constraints. By default, measurePolicy will be invoked in intermediateMeasurePolicy, and hence the same measure logic in measurePolicy with intermediate constraints will be used to measure and layout children in the intermediate pass.

Note: When measurePolicy is invoked in the intermediate pass, subcompose will simply return the measurables associated with the given slot id based on the subcomposition during lookahead pass. This means if a given slot id has not been subcomposed in the lookahead pass, invoking subcompose during intermediate pass will result in an empty list.

Possible use cases:

import androidx.compose.runtime.Composable
import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.unit.IntSize

// In this example, there is a custom modifier that animates the constraints and measures
// child with the animated constraints, as defined below.
// This modifier is built on top of `Modifier.intermediateLayout`, which
// allows access to the lookahead size of the layout. A resize animation will be kicked off
// whenever the lookahead size changes, to animate children from current size to lookahead size.
// Fixed constraints created based on the animation value will be used to measure
// child, so the child layout gradually changes its size and potentially its child's placement
// to fit within the animated constraints.
fun Modifier.animateConstraints() = composed {
    // Creates a size animation
    var sizeAnimation: Animatable<IntSize, AnimationVector2D>? by remember {
        mutableStateOf(null)
    }

    this.intermediateLayout { measurable, _ ->
        // When layout changes, the lookahead pass will calculate a new final size for the
        // child layout. This lookahead size can be used to animate the size
        // change, such that the animation starts from the current size and gradually
        // change towards `lookaheadSize`.
        if (lookaheadSize != sizeAnimation?.targetValue) {
            sizeAnimation?.run {
                launch { animateTo(lookaheadSize) }
            } ?: Animatable(lookaheadSize, IntSize.VectorConverter).let {
                sizeAnimation = it
            }
        }
        val (width, height) = sizeAnimation!!.value
        // Creates a fixed set of constraints using the animated size
        val animatedConstraints = Constraints.fixed(width, height)
        // Measure child with animated constraints.
        val placeable = measurable.measure(animatedConstraints)
        layout(placeable.width, placeable.height) {
            placeable.place(0, 0)
        }
    }
}

// In the example below, the SubcomposeLayout has a parent layout that animates its width
// between two fixed sizes using the `animateConstraints` modifier we created above.
@Composable
fun SubcomposeLayoutWithAnimatingParentLayout(
    isWide: Boolean,
    modifier: Modifier = Modifier,
    content: @Composable @UiComposable () -> Unit
) {
    // Create a MeasurePolicy to measure all children with incoming constraints and return the
    // largest width & height.
    val myMeasurePolicy = MeasurePolicy { measurables, constraints ->
        val placeables = measurables.map { it.measure(constraints) }
        val maxWidth = placeables.maxOf { it.width }
        val maxHeight = placeables.maxOf { it.height }
        layout(maxWidth, maxHeight) {
            placeables.forEach { it.place(0, 0) }
        }
    }
    Box(
        Modifier
            .requiredSize(if (isWide) 400.dp else 200.dp)
            .animateConstraints()
    ) {
        // SubcomposeLayout's measurePolicy will only be invoked with lookahead constraints.
        // The parent layout in this example is animating between two fixed widths. The
        // [measurePolicy] parameter will only be called with lookahead constraints
        // (i.e. constraints for 400.dp x 400.dp or 200.dp x 200.dp depending on the state.)
        // This may cause content lambda to jump to its final size. To create a smooth
        // experience, we need to remeasure the content with the intermediate
        // constraints created by the `animateConstraints` that we built above. Therefore, we
        // need to provide a [intermediateMeasurePolicy] to define how to measure the
        // content (using the measureables of the content that was composed in [measurePolicy])
        // with intermediate constraints.
        SubcomposeLayout(
            modifier,
            intermediateMeasurePolicy = { intermediateConstraints ->
                // Retrieve the measureables for slotId = Unit, and measure them with
                // intermediate constraints using the measurePolicy we created above.
                with(myMeasurePolicy) {
                    measure(
                        measurablesForSlot(Unit),
                        intermediateConstraints
                    )
                }
            },
            measurePolicy = { constraints ->
                val measurables = subcompose(Unit) { content() }
                with(myMeasurePolicy) { measure(measurables, constraints) }
            })
    }
}
Parameters
modifier: Modifier = Modifier

Modifier to apply for the layout.

intermediateMeasurePolicy: SubcomposeIntermediateMeasureScope.(Constraints) -> MeasureResult = { constraints -> lookaheadMeasurePolicy(constraints) }

A measure policy that will be invoked during the intermediate measure pass.

measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult

Measure policy which provides ability to subcompose during the measuring.

SubcomposeLayout

@Composable
@UiComposable
fun SubcomposeLayout(
    state: SubcomposeLayoutState,
    modifier: Modifier = Modifier,
    measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult
): Unit

Analogue of Layout which allows to subcompose the actual content during the measuring stage for example to use the values calculated during the measurement as params for the composition of the children.

Possible use cases:

import androidx.compose.ui.layout.SubcomposeLayout
import androidx.compose.ui.unit.IntSize

// enum class SlotsEnum { Main, Dependent }
SubcomposeLayout { constraints ->
    val mainPlaceables = subcompose(SlotsEnum.Main, mainContent).map {
        it.measure(constraints)
    }
    val maxSize = mainPlaceables.fold(IntSize.Zero) { currentMax, placeable ->
        IntSize(
            width = maxOf(currentMax.width, placeable.width),
            height = maxOf(currentMax.height, placeable.height)
        )
    }
    layout(maxSize.width, maxSize.height) {
        mainPlaceables.forEach { it.placeRelative(0, 0) }
        subcompose(SlotsEnum.Dependent) {
            dependentContent(maxSize)
        }.forEach {
            it.measure(constraints).placeRelative(0, 0)
        }
    }
}
Parameters
state: SubcomposeLayoutState

the state object to be used by the layout.

modifier: Modifier = Modifier

Modifier to apply for the layout.

measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult

Measure policy which provides ability to subcompose during the measuring.

SubcomposeLayout

@Composable
@UiComposable
@ExperimentalComposeUiApi
fun SubcomposeLayout(
    state: SubcomposeLayoutState,
    modifier: Modifier = Modifier,
    intermediateMeasurePolicy: SubcomposeIntermediateMeasureScope.(Constraints) -> MeasureResult = { constraints -> lookaheadMeasurePolicy(constraints) },
    measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult
): Unit

Analogue of Layout which allows to subcompose the actual content during the measuring stage for example to use the values calculated during the measurement as params for the composition of the children.

When in a LookaheadScope, SubcomposeLayout will be measured up to twice per frame. The two measurements will be using different measure policies and potentially different constraints.

The first measurement happens in the lookahead pass, where new layout is calculated based on the target constraints. Therefore, measurePolicy will receive the target constraints, and subcompose its content based on the target constraints. Note: Target constraints refers to the constraints that the SubcomposeLayout will receive once all the lookahead-based animations on size/constraints in the ancestor layouts have finished.

The second measurement is done in the intermediate measure pass after the lookahead pass. The intermediate measure pass allows adjustments to the measurement/placement using the pre-calculated layout information as animation targets to smooth over any any layout changes. In this measurement, intermediateMeasurePolicy will be invoked with the intermediate/animating constraints. By default, measurePolicy will be invoked in intermediateMeasurePolicy, and hence the same measure logic in measurePolicy with intermediate constraints will be used to measure and layout children in the intermediate pass.

Note: When measurePolicy is invoked in the intermediate pass, subcompose will simply return the measurables associated with the given slot id based on the subcomposition during lookahead pass. This means if a given slot id has not been subcomposed in the lookahead pass, invoking subcompose during intermediate pass will result in an empty list.

Possible use cases:

Parameters
state: SubcomposeLayoutState

the state object to be used by the layout.

modifier: Modifier = Modifier

Modifier to apply for the layout.

intermediateMeasurePolicy: SubcomposeIntermediateMeasureScope.(Constraints) -> MeasureResult = { constraints -> lookaheadMeasurePolicy(constraints) }

A measure policy that will be invoked during the intermediate measure pass.

measurePolicy: SubcomposeMeasureScope.(Constraints) -> MeasureResult

Measure policy which provides ability to subcompose during the measuring.

SubcomposeSlotReusePolicy

fun SubcomposeSlotReusePolicy(maxSlotsToRetainForReuse: Int): SubcomposeSlotReusePolicy

Creates SubcomposeSlotReusePolicy which retains the fixed amount of slots.

Parameters
maxSlotsToRetainForReuse: Int

the SubcomposeLayout will retain up to this amount of slots.

lerp

fun lerp(start: ScaleFactor, stop: ScaleFactor, fraction: Float): ScaleFactor

Linearly interpolate between two ScaleFactor parameters

The fraction argument represents position on the timeline, with 0.0 meaning that the interpolation has not started, returning start (or something equivalent to start), 1.0 meaning that the interpolation has finished, returning stop (or something equivalent to stop), and values in between meaning that the interpolation is at the relevant point on the timeline between start and stop. The interpolation can be extrapolated beyond 0.0 and 1.0, so negative values and values greater than 1.0 are valid (and can easily be generated by curves).

Values for fraction are usually obtained from an Animation, such as an AnimationController.

Extension functions

boundsInParent

fun LayoutCoordinates.boundsInParent(): Rect

Returns the bounding box of the child in the parent's content area, including any clipping done with respect to the parent. For the root, the bounds is positioned at (0, 0) and sized to the size of the root.

boundsInRoot

fun LayoutCoordinates.boundsInRoot(): Rect

The boundaries of this layout inside the root composable.

boundsInWindow

fun LayoutCoordinates.boundsInWindow(): Rect

The boundaries of this layout relative to the window's origin.

div

operator fun Size.div(scaleFactor: ScaleFactor): Size

Division operator with Size

Return a new Size with the width and height divided by ScaleFactor.scaleX and ScaleFactor.scaleY respectively

findRootCoordinates

fun LayoutCoordinates.findRootCoordinates(): LayoutCoordinates

Walks up the LayoutCoordinates hierarchy to find the LayoutCoordinates whose LayoutCoordinates.parentCoordinates is null and returns it. If LayoutCoordinates.isAttached, this will have the size of the androidx.compose.ui.platform.ComposeView.

intermediateLayout

@ExperimentalComposeUiApi
fun Modifier.intermediateLayout(
    measure: IntermediateMeasureScope.(measurable: Measurable, constraints: Constraints) -> MeasureResult
): Modifier

Creates an intermediate layout intended to help morph the layout from the current layout to the lookahead (i.e. pre-calculated future) layout.

This modifier will be invoked after lookahead pass and will have access to the lookahead results in measure. Therefore:

  1. intermediateLayout measure/layout logic will not affect lookahead pass, but only be invoked during the main measure/layout pass, and 2) measure block can define intermediate changes that morphs the layout in the main pass gradually until it converges lookahead pass.

import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector2D
import androidx.compose.animation.core.VectorConverter
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.intermediateLayout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.round

// Creates a custom modifier that animates the constraints and measures child with the
// animated constraints. This modifier is built on top of `Modifier.intermediateLayout`, which
// allows access to the lookahead size of the layout. A resize animation will be kicked off
// whenever the lookahead size changes, to animate children from current size to lookahead size.
// Fixed constraints created based on the animation value will be used to measure
// child, so the child layout gradually changes its size and potentially its child's placement
// to fit within the animated constraints.
fun Modifier.animateConstraints() = composed {
    // Creates a size animation
    var sizeAnimation: Animatable<IntSize, AnimationVector2D>? by remember {
        mutableStateOf(null)
    }

    this.intermediateLayout { measurable, _ ->
        // When layout changes, the lookahead pass will calculate a new final size for the
        // child layout. This lookahead size can be used to animate the size
        // change, such that the animation starts from the current size and gradually
        // change towards `lookaheadSize`.
        if (lookaheadSize != sizeAnimation?.targetValue) {
            sizeAnimation?.run {
                launch { animateTo(lookaheadSize) }
            } ?: Animatable(lookaheadSize, IntSize.VectorConverter).let {
                sizeAnimation = it
            }
        }
        val (width, height) = sizeAnimation!!.value
        // Creates a fixed set of constraints using the animated size
        val animatedConstraints = Constraints.fixed(width, height)
        // Measure child with animated constraints.
        val placeable = measurable.measure(animatedConstraints)
        layout(placeable.width, placeable.height) {
            placeable.place(0, 0)
        }
    }
}

var fullWidth by remember { mutableStateOf(false) }
Row(
    (if (fullWidth) Modifier.fillMaxWidth() else Modifier.width(100.dp))
        .height(200.dp)
        // Use the custom modifier created above to animate the constraints passed
        // to the child, and therefore resize children in an animation.
        .animateConstraints()
        .clickable { fullWidth = !fullWidth }) {
    Box(
        Modifier
            .weight(1f)
            .fillMaxHeight()
            .background(Color.Red)
    )
    Box(
        Modifier
            .weight(2f)
            .fillMaxHeight()
            .background(Color.Yellow)
    )
}

layout

fun Modifier.layout(measure: MeasureScope.(Measurable, Constraints) -> MeasureResult): Modifier

Creates a LayoutModifier that allows changing how the wrapped element is measured and laid out.

This is a convenience API of creating a custom LayoutModifier modifier, without having to create a class or an object that implements the LayoutModifier interface. The intrinsic measurements follow the default logic provided by the LayoutModifier.

Example usage:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.layout
import androidx.compose.ui.unit.offset

Box(
    Modifier.background(Color.Gray)
        .layout { measurable, constraints ->
            // an example modifier that adds 50 pixels of vertical padding.
            val padding = 50
            val placeable = measurable.measure(constraints.offset(vertical = -padding))
            layout(placeable.width, placeable.height + padding) {
                placeable.placeRelative(0, padding)
            }
        }
) {
    Box(Modifier.fillMaxSize().background(Color.DarkGray))
}
See also
LayoutModifier

layoutId

fun Modifier.layoutId(layoutId: Any): Modifier

Tag the element with layoutId to identify the element within its parent.

Example usage:

import androidx.compose.foundation.layout.Box
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.unit.Constraints

Layout({
    // Here the Containers are only needed to apply the modifiers. You could use the
    // modifier on header and footer directly if they are composables accepting modifiers.
    Box(Modifier.layoutId("header")) { header() }
    Box(Modifier.layoutId("footer")) { footer() }
}) { measurables, constraints ->
    val placeables = measurables.map { measurable ->
        when (measurable.layoutId) {
            // You should use appropriate constraints. Here we measure fake constraints.
            "header" -> measurable.measure(Constraints.fixed(100, 100))
            "footer" -> measurable.measure(constraints)
            else -> error("Unexpected tag")
        }
    }
    // Size should be derived from children measured sizes on placeables,
    // but this is simplified for the purposes of the example.
    layout(100, 100) {
        placeables.forEach { it.placeRelative(0, 0) }
    }
}

onGloballyPositioned

fun Modifier.onGloballyPositioned(
    onGloballyPositioned: (LayoutCoordinates) -> Unit
): Modifier

Invoke onGloballyPositioned with the LayoutCoordinates of the element when the global position of the content may have changed. Note that it will be called after a composition when the coordinates are finalized.

This callback will be invoked at least once when the LayoutCoordinates are available, and every time the element's position changes within the window. However, it is not guaranteed to be invoked every time the position relative to the screen of the modified element changes. For example, the system may move the contents inside a window around without firing a callback. If you are using the LayoutCoordinates to calculate position on the screen, and not just inside the window, you may not receive a callback.

Usage example:

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.layout.positionInWindow
import androidx.compose.ui.unit.dp

Column(
    Modifier.onGloballyPositioned { coordinates ->
        // This will be the size of the Column.
        coordinates.size
        // The position of the Column relative to the application window.
        coordinates.positionInWindow()
        // The position of the Column relative to the Compose root.
        coordinates.positionInRoot()
        // These will be the alignment lines provided to the layout (empty here for Column).
        coordinates.providedAlignmentLines
        // This will be a LayoutCoordinates instance corresponding to the parent of Column.
        coordinates.parentLayoutCoordinates
    }
) {
    Box(Modifier.size(20.dp).background(Color.Green))
    Box(Modifier.size(20.dp).background(Color.Blue))
}

onPlaced

fun Modifier.onPlaced(onPlaced: (LayoutCoordinates) -> Unit): Modifier

Invoke onPlaced after the parent LayoutModifier and parent layout has been placed and before child LayoutModifier is placed. This allows child LayoutModifier to adjust its own placement based on where the parent is.

import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.AnimationVector2D
import androidx.compose.animation.core.Spring.StiffnessMediumLow
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.spring
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onPlaced
import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.round

@OptIn(ExperimentalComposeUiApi::class)
fun Modifier.animatePlacement(): Modifier = composed {
    val scope = rememberCoroutineScope()
    var targetOffset by remember { mutableStateOf(IntOffset.Zero) }
    var animatable by remember {
        mutableStateOf<Animatable<IntOffset, AnimationVector2D>?>(null)
    }
    this.onPlaced {
        // Calculate the position in the parent layout
        targetOffset = it.positionInParent().round()
    }.offset {
        // Animate to the new target offset when alignment changes.
        val anim = animatable ?: Animatable(targetOffset, IntOffset.VectorConverter)
            .also { animatable = it }
        if (anim.targetValue != targetOffset) {
            scope.launch {
                anim.animateTo(targetOffset, spring(stiffness = StiffnessMediumLow))
            }
        }
        // Offset the child in the opposite direction to the targetOffset, and slowly catch
        // up to zero offset via an animation to achieve an overall animated movement.
        animatable?.let { it.value - targetOffset } ?: IntOffset.Zero
    }
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun AnimatedChildAlignment(alignment: Alignment) {
    Box(
        Modifier.fillMaxSize().padding(4.dp).border(1.dp, Color.Red)
    ) {
        Box(
            modifier = Modifier.animatePlacement().align(alignment).size(100.dp)
                .background(Color.Red)
        )
    }
}

onRelocationRequest

@ExperimentalComposeUiApi
fun Modifier.onRelocationRequest(
    onProvideDestination: (rect: Rect, layoutCoordinates: LayoutCoordinates) -> Rect,
    onPerformRelocation: suspend (sourceRect: Rect, destinationRect: Rect) -> Unit
): Modifier

Add this modifier to respond to requests to bring an item into view.

onSizeChanged

fun Modifier.onSizeChanged(onSizeChanged: (IntSize) -> Unit): Modifier

Invoked with the size of the modified Compose UI element when the element is first measured or when the size of the element changes.

There are no guarantees onSizeChanged will not be re-invoked with the same size.

Using the onSizeChanged size value in a MutableState to update layout causes the new size value to be read and the layout to be recomposed in the succeeding frame, resulting in a one frame lag.

You can use onSizeChanged to affect drawing operations. Use Layout or SubcomposeLayout to enable the size of one component to affect the size of another.

Example usage:

import androidx.compose.material.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onSizeChanged

// Use onSizeChanged() for diagnostics. Use Layout or SubcomposeLayout if you want
// to use the size of one component to affect the size of another component.
Text(
    "Hello $name",
    Modifier.onSizeChanged { size ->
        println("The size of the Text in pixels is $size")
    }
)

positionInParent

fun LayoutCoordinates.positionInParent(): Offset

Returns the position of the top-left in the parent's content area or (0, 0) for the root.

positionInRoot

fun LayoutCoordinates.positionInRoot(): Offset

The position of this layout inside the root composable.

positionInWindow

fun LayoutCoordinates.positionInWindow(): Offset

The position of this layout relative to the window.

relocationRequester

@ExperimentalComposeUiApi
fun Modifier.relocationRequester(relocationRequester: Any): Modifier

This is a modifier that can be used to send relocation requests.

Parameters
relocationRequester: Any

an instance of RelocationRequester. This hoisted object can be used to send relocation requests to parents of the current composable.

takeOrElse

inline fun ScaleFactor.takeOrElse(block: () -> ScaleFactor): ScaleFactor

If this ScaleFactor then this is returned, otherwise block is executed and its result is returned.

times

operator fun Size.times(scaleFactor: ScaleFactor): Size

Multiplication operator with Size.

Return a new Size with the width and height multiplied by the ScaleFactor.scaleX and ScaleFactor.scaleY respectively

times

operator fun ScaleFactor.times(size: Size): Size

Multiplication operator with Size with reverse parameter types to maintain commutative properties of multiplication

Return a new Size with the width and height multiplied by the ScaleFactor.scaleX and ScaleFactor.scaleY respectively

Top-level properties

FirstBaseline

val FirstBaselineHorizontalAlignmentLine

AlignmentLine defined by the baseline of a first line of a androidx.foundation.text.CoreText

LastBaseline

val LastBaselineHorizontalAlignmentLine

AlignmentLine defined by the baseline of the last line of a androidx.foundation.text.CoreText

LocalPinnableContainer

val LocalPinnableContainerProvidableCompositionLocal<PinnableContainer?>

Use this composition local to get the PinnableContainer handling the current subhierarchy.

It will be not null, for example, when the current content is composed as an item of lazy list.

ModifierLocalBeyondBoundsLayout

val ModifierLocalBeyondBoundsLayoutProvidableModifierLocal<BeyondBoundsLayout?>

A modifier local that provides access to a BeyondBoundsLayout that a child can use to ask a parent to layout more items that are beyond its visible bounds.

Extension properties

isSpecified

val ScaleFactor.isSpecifiedBoolean

false when this is ScaleFactor.Unspecified.

isUnspecified

val ScaleFactor.isUnspecifiedBoolean

true when this is ScaleFactor.Unspecified.

layoutId

val Measurable.layoutIdAny?

Retrieves the tag associated to a composable with the Modifier.layoutId modifier. For a parent data value to be returned by this property when not using the Modifier.layoutId modifier, the parent data value should implement the LayoutIdParentData interface.

Example usage:

import androidx.compose.foundation.layout.Box
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.layout.layout
import androidx.compose.ui.layout.layoutId
import androidx.compose.ui.unit.Constraints

Layout({
    // Here the Containers are only needed to apply the modifiers. You could use the
    // modifier on header and footer directly if they are composables accepting modifiers.
    Box(Modifier.layoutId("header")) { header() }
    Box(Modifier.layoutId("footer")) { footer() }
}) { measurables, constraints ->
    val placeables = measurables.map { measurable ->
        when (measurable.layoutId) {
            // You should use appropriate constraints. Here we measure fake constraints.
            "header" -> measurable.measure(Constraints.fixed(100, 100))
            "footer" -> measurable.measure(constraints)
            else -> error("Unexpected tag")
        }
    }
    // Size should be derived from children measured sizes on placeables,
    // but this is simplified for the purposes of the example.
    layout(100, 100) {
        placeables.forEach { it.placeRelative(0, 0) }
    }
}