OnPlacedModifier
-
Cmn
interface OnPlacedModifier : Modifier.Element
A modifier whose onPlaced is called 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.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 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 } } @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) ) } }
Summary
Public functions |
||
|---|---|---|
Unit |
onPlaced(coordinates: LayoutCoordinates)
|
Cmn
|
Inherited functions |
||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
Public functions
onPlaced
fun onPlaced(coordinates: LayoutCoordinates): Unit
onPlaced is called after parent LayoutModifier and parent layout gets placed and before any child LayoutModifier is placed.
coordinates provides LayoutCoordinates of the OnPlacedModifier. Placement in both parent LayoutModifier and parent layout can be calculated using the LayoutCoordinates.