New Compose Multiplatform components arrived on Composables UICheck it out →

Modifier in Compose Ui

onPlaced

Common

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.

Last updated:

Installation

dependencies {
   implementation("androidx.compose.ui:ui:1.7.0-beta04")
}

Overloads

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

Code Example

OnPlaced

@Composable
@Sampled
fun OnPlaced() {
    @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)
            )
        }
    }
}