# LookaheadScope

Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/layout/LookaheadScope.kt+class:androidx.compose.ui.layout.LookaheadScope) Added in [1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.5.0) Common/AllAndroid/JVM
- Cmn

  ```
  interface LookaheadScope
  ```
Known direct subclasses [ExtendedPaneScaffoldScope](https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/layout/ExtendedPaneScaffoldScope), [SharedTransitionScope](https://developer.android.com/reference/kotlin/androidx/compose/animation/SharedTransitionScope)

|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/layout/ExtendedPaneScaffoldScope` | Extended scope for pane scaffolds. |
| `https://developer.android.com/reference/kotlin/androidx/compose/animation/SharedTransitionScope` | `https://developer.android.com/reference/kotlin/androidx/compose/animation/SharedTransitionScope` provides a coordinator space in which shared elements/ shared bounds (when matched) will transform their bounds from one to another. |

Known indirect subclasses [ExtendedPaneScaffoldPaneScope](https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/layout/ExtendedPaneScaffoldPaneScope), [ThreePaneScaffoldPaneScope](https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/layout/ThreePaneScaffoldPaneScope), [ThreePaneScaffoldScope](https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/layout/ThreePaneScaffoldScope)

|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/layout/ExtendedPaneScaffoldPaneScope` | Extended scope for the panes of pane scaffolds. |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/layout/ThreePaneScaffoldPaneScope` | Scope for the panes of `https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/layout/package-summary#ThreePaneScaffold(androidx.compose.ui.Modifier,androidx.compose.material3.adaptive.layout.PaneScaffoldDirective,androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue,androidx.compose.material3.adaptive.layout.ThreePaneScaffoldHorizontalOrder,kotlin.Function1,kotlin.Function1,androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Function2,kotlin.Function1)`. |
| `https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/layout/ThreePaneScaffoldScope` | Scope for the panes of `https://developer.android.com/reference/kotlin/androidx/compose/material3/adaptive/layout/package-summary#ThreePaneScaffold(androidx.compose.ui.Modifier,androidx.compose.material3.adaptive.layout.PaneScaffoldDirective,androidx.compose.material3.adaptive.layout.ThreePaneScaffoldValue,androidx.compose.material3.adaptive.layout.ThreePaneScaffoldHorizontalOrder,kotlin.Function1,kotlin.Function1,androidx.compose.material3.adaptive.layout.PaneExpansionState,kotlin.Function2,kotlin.Function1)`. |

*** ** * ** ***

`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope` provides a receiver scope for all (direct and indirect) child layouts in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope`. This receiver scope allows access to `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.Placeable.PlacementScope).lookaheadScopeCoordinates()` from any child's `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Placeable.PlacementScope`. It also allows any child to convert `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` (which can be retrieved in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Placeable.PlacementScope`) to `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` in lookahead coordinate space using `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).toLookaheadCoordinates()`.

```kotlin
import androidx.compose.animation.core.AnimationVector2D
import androidx.compose.animation.core.DeferredTargetAnimation
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.movableContentOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ApproachLayoutModifierNode
import androidx.compose.ui.layout.ApproachMeasureScope
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.LookaheadScope
import androidx.compose.ui.layout.Measurable
import androidx.compose.ui.layout.MeasureResult
import androidx.compose.ui.layout.Placeable
import androidx.compose.ui.layout.layout
import androidx.compose.ui.node.ModifierNodeElement
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.round

/**
 * 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() }
        }
    }
}
```

## Summary

| ### Public functions |
|---|---|---|
| `open https://developer.android.com/reference/kotlin/androidx/compose/ui/geometry/Offset` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Offset,kotlin.Boolean)( sourceCoordinates: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates, relativeToSource: https://developer.android.com/reference/kotlin/androidx/compose/ui/geometry/Offset, includeMotionFrameOfReference: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html )` Converts `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Offset,kotlin.Boolean)` in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Offset,kotlin.Boolean)`'s lookahead coordinate space into local lookahead coordinates. | Cmn |
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).toLookaheadCoordinates()()` Converts a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` into a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` in the Lookahead coordinate space. | Cmn |

| ### Public properties |
|---|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Placeable.PlacementScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.Placeable.PlacementScope).lookaheadScopeCoordinates()` Returns the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope`. | Cmn |

| ### Extension functions |
|---|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LookaheadScope).lookaheadScopeCoordinates(androidx.compose.ui.layout.LayoutCoordinates)( sourceCoordinates: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates )` Obtains the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` for the given `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope` using a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` within the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope`. | Cmn |

## Public functions

### LayoutCoordinates.localLookaheadPositionOf

Cmn Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/layout/LookaheadScope.kt+function:localLookaheadPositionOf) Added in [1.10.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.10.0)

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

Converts `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Offset,kotlin.Boolean)` in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Offset,kotlin.Boolean)`'s lookahead coordinate space into local lookahead coordinates. This is a convenient method for 1) converting both `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` coordinates and `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Offset,kotlin.Boolean)` into lookahead space coordinates using `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).toLookaheadCoordinates()`, and 2) invoking `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates#localPositionOf(androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Offset)` with the converted coordinates.

For layouts where `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates#introducesMotionFrameOfReference()` returns `true` (placed under `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Placeable.PlacementScope#withMotionFrameOfReferencePlacement(kotlin.Function1)`) you may pass `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).localLookaheadPositionOf(androidx.compose.ui.layout.LayoutCoordinates,androidx.compose.ui.geometry.Offset,kotlin.Boolean)` as `false` to get their position while excluding the additional Offset.

### LayoutCoordinates.toLookaheadCoordinates

Cmn Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/layout/LookaheadScope.kt+function:toLookaheadCoordinates) Added in [1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.5.0)

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

Converts a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` into a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` in the Lookahead coordinate space. This can be used for layouts within `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope`.

## Public properties

### Placeable.PlacementScope.lookaheadScopeCoordinates

Cmn Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/layout/LookaheadScope.kt+symbol:lookaheadScopeCoordinates) Added in [1.5.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.5.0)

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

Returns the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope`. This is only accessible from `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/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 `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope#(androidx.compose.ui.layout.LayoutCoordinates).toLookaheadCoordinates()`.

## Extension functions

### LookaheadScope.lookaheadScopeCoordinates

Cmn Artifact: [androidx.compose.ui:ui](https://developer.android.com/jetpack/androidx/releases/compose-ui) [View Source](https://cs.android.com/search?q=file:androidx/compose/ui/layout/LookaheadScope.kt+function:lookaheadScopeCoordinates)

```
fun LookaheadScope.lookaheadScopeCoordinates(
    sourceCoordinates: LayoutCoordinates
): LayoutCoordinates
```

Obtains the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` for the given `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope` using a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` within the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope`.

**Important:** This must be an actual `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` instance from the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/package-summary#PlacementScope(androidx.compose.ui.node.LookaheadCapablePlaceable)` or `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier` APIs. The Layout that associates with the coordinates needs to be within the subtree of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope`. Using a custom `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` implementation will result in an `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-illegal-argument-exception/index.html`.

| Parameters |
|---|---|
| `sourceCoordinates: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` | A `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates` within the subtree of the given `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LookaheadScope`. |