---
title: "LookaheadScope"
description: "[LookaheadScope] provides a receiver scope for all (direct and indirect) child layouts in
[LookaheadScope]. This receiver scope allows access to [lookaheadScopeCoordinates] from any
child's [Placeable.PlacementScope]. It also allows any child to convert [LayoutCoordinates]
(which can be retrieved in [Placeable.PlacementScope]) to [LayoutCoordinates] in lookahead
coordinate space using [toLookaheadCoordinates]."
type: "interface"
---

<div class='type'>Interface</div>


<a id='references'></a>

<div class='sourceset sourceset-common'>Common</div>



```kotlin
interface LookaheadScope
```


`LookaheadScope` provides a receiver scope for all (direct and indirect) child layouts in
`LookaheadScope`. This receiver scope allows access to `lookaheadScopeCoordinates` from any
child's `Placeable.PlacementScope`. It also allows any child to convert `LayoutCoordinates`
(which can be retrieved in `Placeable.PlacementScope`) to `LayoutCoordinates` in lookahead
coordinate space using `toLookaheadCoordinates`.


## Properties

<div class='sourceset sourceset-common'>Common</div>


```kotlin
val Placeable.PlacementScope.lookaheadScopeCoordinates: LayoutCoordinates
```


Returns the `LayoutCoordinates` of the `LookaheadScope`. This is only accessible from
`Placeable.PlacementScope` (i.e. during placement time).

Note: The returned coordinates is **not** coordinates in the lookahead coordinate space. If
the lookahead coordinates of the lookaheadScope is needed, suggest converting the returned
coordinates using `toLookaheadCoordinates`.



## Functions

```kotlin
fun LayoutCoordinates.toLookaheadCoordinates(): LayoutCoordinates
```


Converts a `LayoutCoordinates` into a `LayoutCoordinates` in the Lookahead coordinate space.
This can be used for layouts within `LookaheadScope`.


```kotlin
fun LayoutCoordinates.localLookaheadPositionOf(
        sourceCoordinates: LayoutCoordinates,
        relativeToSource: Offset = Offset.Zero,
        includeMotionFrameOfReference: Boolean = true,
    ): Offset
```


Converts `relativeToSource` in `sourceCoordinates`'s lookahead coordinate space into local
lookahead coordinates. This is a convenient method for 1) converting both `this` coordinates
and `sourceCoordinates` into lookahead space coordinates using `toLookaheadCoordinates`,
and 2) invoking `LayoutCoordinates.localPositionOf` with the converted coordinates.

For layouts where `LayoutCoordinates.introducesMotionFrameOfReference` returns `true` (placed
under `Placeable.PlacementScope.withMotionFrameOfReferencePlacement`) you may pass
`includeMotionFrameOfReference` as `false` to get their position while excluding the
additional Offset.



## Code Examples

### LookaheadLayoutCoordinatesSample
```kotlin
@OptIn(ExperimentalAnimatableApi::class)
@Composable
fun LookaheadLayoutCoordinatesSample() {
    /**
     * Creates a custom implementation of ApproachLayoutModifierNode to approach the placement of
     * the layout using an animation.
     */
    class AnimatedPlacementModifierNode(var lookaheadScope: LookaheadScope) :
        ApproachLayoutModifierNode, Modifier.Node() {
        // Creates an offset animation, the target of which will be known during placement.
        val offsetAnimation: DeferredTargetAnimation<IntOffset, AnimationVector2D> =
            DeferredTargetAnimation(IntOffset.VectorConverter)
        override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
            // Since we only animate the placement here, we can consider measurement approach
            // complete.
            return false
        }
        // Returns true when the offset animation is in progress, false otherwise.
        override fun Placeable.PlacementScope.isPlacementApproachInProgress(
            lookaheadCoordinates: LayoutCoordinates
        ): Boolean {
            val target =
                with(lookaheadScope) {
                    lookaheadScopeCoordinates.localLookaheadPositionOf(lookaheadCoordinates).round()
                }
            offsetAnimation.updateTarget(target, coroutineScope)
            return !offsetAnimation.isIdle
        }
        override fun ApproachMeasureScope.approachMeasure(
            measurable: Measurable,
            constraints: Constraints,
        ): MeasureResult {
            val placeable = measurable.measure(constraints)
            return layout(placeable.width, placeable.height) {
                val coordinates = coordinates
                if (coordinates != null) {
                    // Calculates the target offset within the lookaheadScope
                    val target =
                        with(lookaheadScope) {
                            lookaheadScopeCoordinates.localLookaheadPositionOf(coordinates).round()
                        }
                    // Uses the target offset to start an offset animation
                    val animatedOffset = offsetAnimation.updateTarget(target, coroutineScope)
                    // Calculates the *current* offset within the given LookaheadScope
                    val placementOffset =
                        with(lookaheadScope) {
                            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) = animatedOffset - placementOffset
                    placeable.place(x, y)
                } else {
                    placeable.place(0, 0)
                }
            }
        }
    }
    // Creates a custom node element for the AnimatedPlacementModifierNode above.
    data class AnimatePlacementNodeElement(val lookaheadScope: LookaheadScope) :
        ModifierNodeElement<AnimatedPlacementModifierNode>() {
        override fun update(node: AnimatedPlacementModifierNode) {
            node.lookaheadScope = lookaheadScope
        }
        override fun create(): AnimatedPlacementModifierNode {
            return AnimatedPlacementModifierNode(lookaheadScope)
        }
    }
    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)
                            .then(AnimatePlacementNodeElement(this))
                            .background(color, RoundedCornerShape(20))
                    )
                }
            }
        }
        Box(modifier = Modifier.fillMaxSize().clickable { isInColumn = !isInColumn }) {
            // As the items get moved between Column and Row, their positions in LookaheadScope
            // 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() }
            }
        }
    }
}
```

