# ApproachLayoutModifierNode

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/ApproachLayoutModifierNode.kt+class:androidx.compose.ui.layout.ApproachLayoutModifierNode) Added in [1.7.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.0) Common/AllAndroid/JVM
- Cmn

  ```
  interface ApproachLayoutModifierNode : LayoutModifierNode
  ```

*** ** * ** ***

`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode` is designed to support gradually approaching the destination layout calculated in the lookahead pass. This can be particularly helpful when the destination layout is anticipated to change drastically and would consequently result in visual disruptions.

In order to create a smooth approach, an interpolation (often through animations) can be used in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` to interpolate the measurement or placement from a previously recorded size and/or position to the destination/target size and/or position. The destination size is available in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachMeasureScope` as `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachIntrinsicMeasureScope#lookaheadSize()`. And the target position can also be acquired in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachMeasureScope` during placement by using `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)` with the layout's `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Placeable.PlacementScope#coordinates()`. The sample code below illustrates how that can be achieved.

During the lookahead pass, `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.MeasureScope).measure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` will be invoked. By default `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.MeasureScope).measure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` simply passes the incoming constraints to its child, and returns the child measure result to parent without any modification. The default behavior for `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.MeasureScope).measure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` is simply a pass through of constraints and measure results without modification. This can be overridden as needed. `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` will be invoked during the approach pass after lookahead.

`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)` signals whether the measurement is in progress of approaching destination size. It will be queried after the destination has been determined by the lookahead pass, before `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` is invoked. The lookahead size is provided to `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)` for convenience in deciding whether the destination size has been reached.

`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` indicates whether the position is actively approaching destination defined by the lookahead, hence it's a signal to the system for whether additional approach placements are necessary. `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` will be invoked after the destination position has been determined by lookahead pass, and before the placement phase in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)`.

**IMPORTANT** : When both `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)` and `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` become false, the approach is considered complete. Approach pass will subsequently snap the measurement and placement to lookahead measurement and placement. Once approach is complete, `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` may never be invoked until either `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)` or `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` becomes true again. Therefore it is important to ensure `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` and `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.MeasureScope).measure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` result in the same measurement and placement when the approach is complete. Otherwise, there may be visual discontinuity when we snap the measurement and placement to lookahead.

It is important to be accurate in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` and `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)`. A prolonged indication of incomplete approach will prevent the system from potentially skipping approach pass when possible.

```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 |
|---|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/MeasureResult` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachMeasureScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)( measurable: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Measurable, constraints: https://developer.android.com/reference/kotlin/androidx/compose/ui/unit/Constraints )` `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` defines how the measurement and placement of the layout approach the destination size and position. | Cmn |
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)(lookaheadSize: https://developer.android.com/reference/kotlin/androidx/compose/ui/unit/IntSize)` `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)` signals whether the measurement is currently approaching destination size. | Cmn |
| `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-boolean/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Placeable.PlacementScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)( lookaheadCoordinates: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/LayoutCoordinates )` `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` indicates whether the position is approaching destination defined by the lookahead, hence it's a signal to the system for whether additional approach placements are necessary. | Cmn |
| `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachIntrinsicMeasureScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope).maxApproachIntrinsicHeight(androidx.compose.ui.layout.IntrinsicMeasurable,kotlin.Int)( measurable: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable, width: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html )` The function used to calculate maxIntrinsicHeight for the approach pass changes. | Cmn |
| `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachIntrinsicMeasureScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope).maxApproachIntrinsicWidth(androidx.compose.ui.layout.IntrinsicMeasurable,kotlin.Int)( measurable: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable, height: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html )` The function used to calculate maxIntrinsicWidth for the approach pass changes. | Cmn |
| `open https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/MeasureResult` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/MeasureScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.MeasureScope).measure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)(measurable: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Measurable, constraints: https://developer.android.com/reference/kotlin/androidx/compose/ui/unit/Constraints)` The function used to measure the modifier. | Cmn |
| `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachIntrinsicMeasureScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope).minApproachIntrinsicHeight(androidx.compose.ui.layout.IntrinsicMeasurable,kotlin.Int)( measurable: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable, width: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html )` The function used to calculate minIntrinsicHeight for the approach pass changes. | Cmn |
| `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html` | `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachIntrinsicMeasureScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachIntrinsicMeasureScope).minApproachIntrinsicWidth(androidx.compose.ui.layout.IntrinsicMeasurable,kotlin.Int)( measurable: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable, height: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html )` The function used to calculate minIntrinsicWidth for the approach pass changes. | Cmn |

### Inherited functions

From [androidx.compose.ui.node.DelegatableNode](https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode) `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` `@https://developer.android.com/reference/kotlin/androidx/annotation/EmptySuper
https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode#onDensityChange()()`

Invoked when the density changes for this node.
Cmn `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` `@https://developer.android.com/reference/kotlin/androidx/annotation/EmptySuper
https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode#onLayoutDirectionChange()()`

Invoked when the layout direction changes for this node.
Cmn From [androidx.compose.ui.node.LayoutModifierNode](https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode) `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html` `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasureScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode#(androidx.compose.ui.layout.IntrinsicMeasureScope).maxIntrinsicHeight(androidx.compose.ui.layout.IntrinsicMeasurable,kotlin.Int)(
measurable: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable,
width: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html
)`

The lambda used to calculate `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable#maxIntrinsicHeight(kotlin.Int)`.
Cmn `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html` `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasureScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode#(androidx.compose.ui.layout.IntrinsicMeasureScope).maxIntrinsicWidth(androidx.compose.ui.layout.IntrinsicMeasurable,kotlin.Int)(
measurable: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable,
height: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html
)`

The function used to calculate `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable#maxIntrinsicWidth(kotlin.Int)`.
Cmn `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html` `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasureScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode#(androidx.compose.ui.layout.IntrinsicMeasureScope).minIntrinsicHeight(androidx.compose.ui.layout.IntrinsicMeasurable,kotlin.Int)(
measurable: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable,
width: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html
)`

The lambda used to calculate `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable#minIntrinsicHeight(kotlin.Int)`.
Cmn `open https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html` `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasureScope.https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode#(androidx.compose.ui.layout.IntrinsicMeasureScope).minIntrinsicWidth(androidx.compose.ui.layout.IntrinsicMeasurable,kotlin.Int)(
measurable: https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable,
height: https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-int/index.html
)`

The function used to calculate `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/IntrinsicMeasurable#minIntrinsicWidth(kotlin.Int)`.
Cmn

### Inherited properties

From [androidx.compose.ui.node.DelegatableNode](https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode) `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/DelegatableNode#node()`

A reference of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier.Node` that holds this node's position in the node hierarchy.
Cmn

## Public functions

### ApproachMeasureScope.approachMeasure

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/ApproachLayoutModifierNode.kt+function:approachMeasure) Added in [1.10.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.10.0)

```
fun ApproachMeasureScope.approachMeasure(
    measurable: Measurable,
    constraints: Constraints
): MeasureResult
```

`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` defines how the measurement and placement of the layout approach the destination size and position. In order to achieve a smooth approach from the current size and position to the destination, an interpolation (often through animations) can be used in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` to interpolate the measurement or placement from a previously recorded size and position to the destination/target size and position. The destination size is available in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachMeasureScope` as `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachIntrinsicMeasureScope#lookaheadSize()`. And the target position can also be acquired in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachMeasureScope` during placement by using `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)` with the layout's `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Placeable.PlacementScope#coordinates()`. Please see sample code below for how that can be achieved.

Note: `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` is only guaranteed to be invoked when either `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)` or `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)` is true. Otherwise, the system will consider the approach complete (i.e. destination reached) and may skip the approach pass when possible.

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

### isMeasurementApproachInProgress

Cmn Added in [1.10.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.10.0)

```
fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean
```

`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)` signals whether the measurement is currently approaching destination size. It will be queried after the destination has been determined by the lookahead pass, before `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` is invoked. The lookahead size is provided to `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)` for convenience in deciding whether the destination size has been reached.

Note: It is important to be accurate in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` and `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)`. A prolonged indication of incomplete approach will prevent the system from potentially skipping approach pass when possible.

### Placeable.PlacementScope.isPlacementApproachInProgress

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/ApproachLayoutModifierNode.kt+function:isPlacementApproachInProgress) Added in [1.7.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.0)

```
open fun Placeable.PlacementScope.isPlacementApproachInProgress(
    lookaheadCoordinates: LayoutCoordinates
): Boolean
```

`https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` indicates whether the position is approaching destination defined by the lookahead, hence it's a signal to the system for whether additional approach placements are necessary. `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` will be invoked after the destination position has been determined by lookahead pass, and before the placement phase in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.ApproachMeasureScope).approachMeasure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)`.

Note: It is important to be accurate in `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` and `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#isMeasurementApproachInProgress(androidx.compose.ui.unit.IntSize)`. A prolonged indication of incomplete approach will prevent the system from potentially skipping approach pass when possible.

By default, `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ApproachLayoutModifierNode#(androidx.compose.ui.layout.Placeable.PlacementScope).isPlacementApproachInProgress(androidx.compose.ui.layout.LayoutCoordinates)` returns false.

### ApproachIntrinsicMeasureScope.maxApproachIntrinsicHeight

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/ApproachLayoutModifierNode.kt+function:maxApproachIntrinsicHeight) Added in [1.7.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.0)

```
open fun ApproachIntrinsicMeasureScope.maxApproachIntrinsicHeight(
    measurable: IntrinsicMeasurable,
    width: Int
): Int
```

The function used to calculate maxIntrinsicHeight for the approach pass changes.

### ApproachIntrinsicMeasureScope.maxApproachIntrinsicWidth

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/ApproachLayoutModifierNode.kt+function:maxApproachIntrinsicWidth) Added in [1.7.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.0)

```
open fun ApproachIntrinsicMeasureScope.maxApproachIntrinsicWidth(
    measurable: IntrinsicMeasurable,
    height: Int
): Int
```

The function used to calculate maxIntrinsicWidth for the approach pass changes.

### MeasureScope.measure

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/ApproachLayoutModifierNode.kt+function:measure)

```
open fun MeasureScope.measure(measurable: Measurable, constraints: Constraints): MeasureResult
```

The function used to measure the modifier. The `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode#(androidx.compose.ui.layout.MeasureScope).measure(androidx.compose.ui.layout.Measurable,androidx.compose.ui.unit.Constraints)` corresponds to the wrapped content, and it can be measured with the desired constraints according to the logic of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode`. The modifier needs to choose its own size, which can depend on the size chosen by the wrapped content (the obtained `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Placeable`), if the wrapped content was measured. The size needs to be returned as part of a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/MeasureResult`, alongside the placement logic of the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Placeable`, which defines how the wrapped content should be positioned inside the `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode`. A convenient way to create the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/MeasureResult` is to use the `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/MeasureScope#layout(kotlin.Int,kotlin.Int,kotlin.collections.Map,kotlin.Function1)` factory function.

A `https://developer.android.com/reference/kotlin/androidx/compose/ui/node/LayoutModifierNode` uses the same measurement and layout concepts and principles as a `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/Layout.composable#Layout(kotlin.Function0,androidx.compose.ui.Modifier,androidx.compose.ui.layout.MeasurePolicy)`, the only difference is that they apply to exactly one child. For a more detailed explanation of measurement and layout, see `https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/MeasurePolicy`.

### ApproachIntrinsicMeasureScope.minApproachIntrinsicHeight

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/ApproachLayoutModifierNode.kt+function:minApproachIntrinsicHeight) Added in [1.7.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.0)

```
open fun ApproachIntrinsicMeasureScope.minApproachIntrinsicHeight(
    measurable: IntrinsicMeasurable,
    width: Int
): Int
```

The function used to calculate minIntrinsicHeight for the approach pass changes.

### ApproachIntrinsicMeasureScope.minApproachIntrinsicWidth

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/ApproachLayoutModifierNode.kt+function:minApproachIntrinsicWidth) Added in [1.7.0](https://developer.android.com/jetpack/androidx/releases/compose-ui#1.7.0)

```
open fun ApproachIntrinsicMeasureScope.minApproachIntrinsicWidth(
    measurable: IntrinsicMeasurable,
    height: Int
): Int
```

The function used to calculate minIntrinsicWidth for the approach pass changes.