androidx.compose.animation
In this page, you'll find documentation for types, properties, and functions available in the androidx.compose.animation package. For example:
-
Animation APIs such as
Animatable,AnimatedVisibility, andanimateContentSize. -
Enter/exit animation APIs such as
fadeIn,slideOut,expandHorizontally, andCrossfade.
If you're looking for guidance instead, check out the Animations in Compose guide.
Interfaces
AnimatedContentScope |
Receiver scope for content lambda for AnimatedContent. |
Cmn
|
AnimatedContentTransitionScope |
|
Cmn
|
AnimatedVisibilityScope |
This is the scope for the content of |
Cmn
|
BoundsTransform |
|
Cmn
|
SharedTransitionScope |
|
Cmn
|
SharedTransitionScope.OverlayClip |
|
Cmn
|
SharedTransitionScope.PlaceholderSize |
PlaceholderSize defines the size of the space that was or will be occupied by the exiting or entering |
Cmn
|
SharedTransitionScope.ResizeMode |
There are two different modes to resize child layout of |
Cmn
|
SharedTransitionScope.SharedContentConfig |
|
Cmn
|
SizeTransform |
|
Cmn
|
TransformScope |
Scope for manually manipulating the visual transformation of content during the deferred phase of a |
Cmn
|
Classes
AnimatedContentTransitionScope.SlideDirection |
|
Cmn
|
ContentTransform |
|
Cmn
|
EnterTransition |
|
Cmn
|
ExitTransition |
|
Cmn
|
MutableContentTransform |
An object that allows manual manipulation of both entering and exiting content during the deferred phase (initiated by |
Cmn
|
MutableTransform |
An object that allows manual manipulation of the visual transformations (alpha, scale, offset, etc.) of content during the deferred phase (initiated by |
Cmn
|
SharedTransitionScope.SharedContentState |
|
Cmn
|
SplineBasedFloatDecayAnimationSpec |
A native Android fling curve decay. |
Cmn
|
Objects
SharedTransitionDefaults |
Default values for |
Cmn
|
SharedTransitionDefaults.SharedContentConfig |
Default SharedContentConfig used in |
Cmn
|
Annotations
ExperimentalAnimationApi |
Cmn
|
|
ExperimentalLookaheadAnimationVisualDebugApi |
Cmn
|
|
ExperimentalSharedTransitionApi |
Cmn
|
Enums
EnterExitState |
|
Cmn
|
Composables
AnimatedContent |
|
Cmn
|
AnimatedVisibility |
|
Cmn
|
Crossfade |
|
Cmn
|
CustomizedLookaheadAnimationVisualDebugging |
Allows customizing a particular shared element or animated bounds animation for debugging. |
Cmn
|
DeferredAnimatedContent |
|
Cmn
|
DeferredAnimatedVisibility |
|
Cmn
|
LookaheadAnimationVisualDebugging |
Allows enabling and customizing shared element and animated bounds animation debugging. |
Cmn
|
SharedTransitionLayout |
|
Cmn
|
SharedTransitionScope |
|
Cmn
|
animateColor |
Creates a Color animation that runs infinitely as a part of the given |
Cmn
|
animateColorAsState |
Fire-and-forget animation function for |
Cmn
|
defaultDecayAnimationSpec |
Create default |
Cmn
android
|
rememberSplineBasedDecay |
Cmn
android
|
Modifiers
animateBounds |
|
Cmn
|
animateContentSize |
This modifier animates its own size when its child modifier (or the child composable if it is already at the tail of the chain) changes size. |
Cmn
|
Top-level functions summary
Animatable<Color, AnimationVector4D> |
@RememberInCompositionThis |
Cmn
|
inline MutableContentTransform |
@ExperimentalDeferredTransitionApiCreates a |
Cmn
|
SizeTransform |
SizeTransform(This creates a |
Cmn
|
EnterTransition |
expandHorizontally(This expands the clip bounds of the appearing content horizontally, from the width returned from |
Cmn
|
EnterTransition |
expandIn(This expands the clip bounds of the appearing content from the size returned from |
Cmn
|
EnterTransition |
expandVertically(This expands the clip bounds of the appearing content vertically, from the height returned from |
Cmn
|
EnterTransition |
fadeIn(animationSpec: FiniteAnimationSpec<Float>, initialAlpha: Float)This fades in the content of the transition, from the specified starting alpha (i.e. |
Cmn
|
ExitTransition |
fadeOut(animationSpec: FiniteAnimationSpec<Float>, targetAlpha: Float)This fades out the content of the transition, from full opacity to the specified target alpha (i.e. |
Cmn
|
EnterTransition |
scaleIn(This scales the content as it appears, from an initial scale (defined in |
Cmn
|
ExitTransition |
scaleOut(This scales the content of the exit transition, from 1f to the target scale defined in |
Cmn
|
ExitTransition |
shrinkHorizontally(This shrinks the clip bounds of the disappearing content horizontally, from the full width to the width returned from |
Cmn
|
ExitTransition |
shrinkOut(This shrinks the clip bounds of the disappearing content from the full size to the size returned from |
Cmn
|
ExitTransition |
shrinkVertically(This shrinks the clip bounds of the disappearing content vertically, from the full height to the height returned from |
Cmn
|
EnterTransition |
slideIn(This slides in the content of the transition, from a starting offset defined in |
Cmn
|
EnterTransition |
slideInHorizontally(This slides in the content horizontally, from a starting offset defined in |
Cmn
|
EnterTransition |
slideInVertically(This slides in the content vertically, from a starting offset defined in |
Cmn
|
ExitTransition |
slideOut(This slides out the content of the transition, from an offset of |
Cmn
|
ExitTransition |
slideOutHorizontally(This slides out the content horizontally, from 0 to a target offset defined in |
Cmn
|
ExitTransition |
slideOutVertically(This slides out the content vertically, from 0 to a target offset defined in |
Cmn
|
DecayAnimationSpec<T> |
<T : Any?> splineBasedDecay(density: Density) |
Cmn
|
EnterTransition |
@ExperimentalAnimationApiThis animates an unveiling scrim over the content as it enters. |
Cmn
|
ExitTransition |
@ExperimentalAnimationApiThis animates a veiling scrim over the content as it exits. |
Cmn
|
Extension functions summary
infix ContentTransform |
This creates a |
Cmn
|
infix ContentTransform |
This function is deprecated. Infix fun EnterTransition.with(ExitTransition) has been renamed to togetherWith |
Cmn
|
Extension properties summary
(colorSpace: ColorSpace) -> TwoWayConverter<Color, AnimationVector4D> |
A lambda that takes a |
Cmn
|
Top-level functions
Animatable
@RememberInComposition
fun Animatable(initialValue: Color): Animatable<Color, AnimationVector4D>
This Animatable function creates a Color value holder that automatically animates its value when the value is changed via animateTo. Animatable supports value change during an ongoing value change animation. When that happens, a new animation will transition Animatable from its current value (i.e. value at the point of interruption) to the new target. This ensures that the value change is always continuous using animateTo. If spring animation (i.e. default animation) is used with animateTo, the velocity change will be guaranteed to be continuous as well.
Unlike AnimationState, Animatable ensures mutual exclusiveness on its animation. To do so, when a new animation is started via animateTo (or animateDecay), any ongoing animation job will be cancelled via a CancellationException.
Animatable also supports animating data types other than Color, such as Floats and generic types. See androidx.compose.animation.core.Animatable for other variants.
import androidx.compose.animation.Animatable import androidx.compose.animation.core.AnimationSpec import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.graphics.Color @Composable fun animate( targetValue: Color, animationSpec: AnimationSpec<Color>, onFinished: (Color) -> Unit, ): Color { // Creates an Animatable of Color, and remembers it. val color = remember { Animatable(targetValue) } val finishedListener = rememberUpdatedState(onFinished) // Launches a new coroutine whenever the target value or animation spec has changed. This // automatically cancels the previous job/animation. LaunchedEffect(targetValue, animationSpec) { color.animateTo(targetValue, animationSpec) // Invokes finished listener. This line will not be executed if the job gets canceled // halfway through an animation. finishedListener.value(targetValue) } return color.value }
| Parameters | |
|---|---|
initialValue: Color |
initial value of the |
MutableContentTransform
@ExperimentalDeferredTransitionApi
inline fun MutableContentTransform(
initialVeilMatchParentSize: Boolean = false,
targetVeilMatchParentSize: Boolean = false,
noinline initialOffsetVelocityProvider: (() -> Offset)? = null,
noinline targetOffsetVelocityProvider: (() -> Offset)? = null,
block: MutableContentTransform.() -> Unit = {}
): MutableContentTransform
Creates a MutableContentTransform and applies the provided configuration block.
| Parameters | |
|---|---|
initialVeilMatchParentSize: Boolean = false |
Whether the initial content's veil should match the parent size. |
targetVeilMatchParentSize: Boolean = false |
Whether the target content's veil should match the parent size. |
noinline initialOffsetVelocityProvider: (() -> Offset)? = null |
The velocity of the offset change for the exiting content in pixels/sec. If |
noinline targetOffsetVelocityProvider: (() -> Offset)? = null |
The velocity of the offset change for the entering content in pixels/sec. If |
block: MutableContentTransform.() -> Unit = {} |
A configuration block to set up the transformations for initial and target content. |
SizeTransform
fun SizeTransform(
clip: Boolean = true,
sizeAnimationSpec: (initialSize: IntSize, targetSize: IntSize) -> FiniteAnimationSpec<IntSize> = { _, _ -> spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold, ) }
): SizeTransform
This creates a SizeTransform with the provided clip and sizeAnimationSpec. By default, clip will be true. This means during the size animation, the content will be clipped to the animated size. sizeAnimationSpec defaults to return a spring animation.
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.ContentTransform import androidx.compose.animation.SizeTransform import androidx.compose.animation.core.keyframes import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith import androidx.compose.ui.unit.IntSize // enum class CartState { Expanded, Collapsed } val transitionSpec: AnimatedContentTransitionScope<CartState>.() -> ContentTransform = { // Fade in with a delay so that it starts after fade out fadeIn(animationSpec = tween(150, delayMillis = 150)) .togetherWith(fadeOut(animationSpec = tween(150))) .using( SizeTransform { initialSize, targetSize -> // Using different SizeTransform for different state change if (CartState.Collapsed isTransitioningTo CartState.Expanded) { keyframes { durationMillis = 500 // Animate to full target width and by 200px in height at 150ms IntSize(targetSize.width, initialSize.height + 200) at 150 } } else { keyframes { durationMillis = 500 // Animate 1/2 the height without changing the width at 150ms. // The width and rest of the height will be animated in the // timeframe between 150ms and duration (i.e. 500ms) IntSize( initialSize.width, (initialSize.height + targetSize.height) / 2, ) at 150 } } } ) }
expandHorizontally
fun expandHorizontally(
animationSpec: FiniteAnimationSpec<IntSize> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold, ),
expandFrom: Alignment.Horizontal = Alignment.End,
clip: Boolean = true,
initialWidth: (fullWidth: Int) -> Int = { 0 }
): EnterTransition
This expands the clip bounds of the appearing content horizontally, from the width returned from initialWidth to the full width. expandFrom controls which part of the content gets revealed first. By default, the clip bounds animates from 0 to full width, starting from the end of the content, and expand to fully revealing the whole content.
Note: expandHorizontally animates the bounds of the content. This bounds change will also result in the animation of other layouts that are dependent on this size.
initialWidth is a lambda that takes the full width of the content and returns an initial width of the bounds of the content. This allows not only an absolute width, but also an initial width that is proportional to the content width.
clip defines whether the content outside of the animated bounds should be clipped. By default, clip is set to true, which only shows content in the animated bounds.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween import androidx.compose.animation.expandHorizontally import androidx.compose.animation.shrinkHorizontally import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.width import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, // Set the start width to 20 (pixels), 0 by default enter = expandHorizontally { 20 }, exit = shrinkHorizontally( // Overwrites the default animation with tween for this shrink animation. animationSpec = tween(), // Shrink towards the end (i.e. right edge for LTR, left edge for RTL). The default // direction for the shrink is towards [Alignment.Start] shrinkTowards = Alignment.End, ) { fullWidth -> // Set the end width for the shrink animation to a quarter of the full width. fullWidth / 4 }, ) { // Content that needs to appear/disappear goes here: Box(Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntSize> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntSize.VisibilityThreshold,
) |
the animation used for the expanding animation, |
expandFrom: Alignment.Horizontal = Alignment.End |
the starting point of the expanding bounds, |
clip: Boolean = true |
whether the content outside of the animated bounds should be clipped, true by default |
initialWidth: (fullWidth: Int) -> Int = { 0 } |
the start width of the expanding bounds, returning 0 by default. |
expandIn
fun expandIn(
animationSpec: FiniteAnimationSpec<IntSize> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold, ),
expandFrom: Alignment = Alignment.BottomEnd,
clip: Boolean = true,
initialSize: (fullSize: IntSize) -> IntSize = { IntSize(0, 0) }
): EnterTransition
This expands the clip bounds of the appearing content from the size returned from initialSize to the full size. expandFrom controls which part of the content gets revealed first. By default, the clip bounds animates from IntSize(0, 0) to full size, starting from revealing the bottom right corner (or bottom left corner in RTL layouts) of the content, to fully revealing the entire content as the size expands.
Note: expandIn animates the bounds of the content. This bounds change will also result in the animation of other layouts that are dependent on this size.
initialSize is a lambda that takes the full size of the content and returns an initial size of the bounds of the content. This allows not only absolute size, but also an initial size that is proportional to the content size.
clip defines whether the content outside of the animated bounds should be clipped. By default, clip is set to true, which only shows content in the animated bounds.
For expanding only horizontally or vertically, consider expandHorizontally, expandVertically.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.LinearOutSlowInEasing import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.animation.expandIn import androidx.compose.animation.shrinkOut import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible, enter = expandIn( // Overwrites the default spring animation with tween animationSpec = tween(100, easing = LinearOutSlowInEasing), // Overwrites the corner of the content that is first revealed expandFrom = Alignment.BottomStart, ) { // Overwrites the initial size to 50 pixels by 50 pixels IntSize(50, 50) }, exit = shrinkOut( tween(100, easing = FastOutSlowInEasing), // Overwrites the area of the content that the shrink animation will end on. The // following parameters will shrink the content's clip bounds from the full size of // the // content to 1/10 of the width and 1/5 of the height. The shrinking clip bounds // will // always be aligned to the CenterStart of the full-content bounds. shrinkTowards = Alignment.CenterStart, ) { fullSize -> // Overwrites the target size of the shrinking animation. IntSize(fullSize.width / 10, fullSize.height / 5) }, ) { // Content that needs to appear/disappear goes here: Text("Content to appear/disappear", Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntSize> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntSize.VisibilityThreshold,
) |
the animation used for the expanding animation, |
expandFrom: Alignment = Alignment.BottomEnd |
the starting point of the expanding bounds, |
clip: Boolean = true |
whether the content outside of the animated bounds should be clipped, true by default |
initialSize: (fullSize: IntSize) -> IntSize = { IntSize(0, 0) } |
the start size of the expanding bounds, returning |
expandVertically
fun expandVertically(
animationSpec: FiniteAnimationSpec<IntSize> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold, ),
expandFrom: Alignment.Vertical = Alignment.Bottom,
clip: Boolean = true,
initialHeight: (fullHeight: Int) -> Int = { 0 }
): EnterTransition
This expands the clip bounds of the appearing content vertically, from the height returned from initialHeight to the full height. expandFrom controls which part of the content gets revealed first. By default, the clip bounds animates from 0 to full height, revealing the bottom edge first, followed by the rest of the content.
Note: expandVertically animates the bounds of the content. This bounds change will also result in the animation of other layouts that are dependent on this size.
initialHeight is a lambda that takes the full height of the content and returns an initial height of the bounds of the content. This allows not only an absolute height, but also an initial height that is proportional to the content height.
clip defines whether the content outside of the animated bounds should be clipped. By default, clip is set to true, which only shows content in the animated bounds.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.requiredHeight import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible, // Sets the initial height of the content to 20, revealing only the top of the content at // the beginning of the expanding animation. enter = expandVertically(expandFrom = Alignment.Top) { 20 }, // Shrinks the content to half of its full height via an animation. exit = shrinkVertically(animationSpec = tween()) { fullHeight -> fullHeight / 2 }, ) { // Content that needs to appear/disappear goes here: Text("Content to appear/disappear", Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntSize> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntSize.VisibilityThreshold,
) |
the animation used for the expanding animation, |
expandFrom: Alignment.Vertical = Alignment.Bottom |
the starting point of the expanding bounds, |
clip: Boolean = true |
whether the content outside of the animated bounds should be clipped, true by default |
initialHeight: (fullHeight: Int) -> Int = { 0 } |
the start height of the expanding bounds, returning 0 by default. |
fadeIn
fun fadeIn(
animationSpec: FiniteAnimationSpec<Float> = spring(stiffness = Spring.StiffnessMediumLow),
initialAlpha: Float = 0.0f
): EnterTransition
This fades in the content of the transition, from the specified starting alpha (i.e. initialAlpha) to 1f, using the supplied animationSpec. initialAlpha defaults to 0f, and spring is used by default.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.requiredHeight import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = fadeIn( // Overwrites the initial value of alpha to 0.4f for fade in, 0 by default initialAlpha = 0.4f ), exit = fadeOut( // Overwrites the default animation with tween animationSpec = tween(durationMillis = 250) ), ) { // Content that needs to appear/disappear goes here: Text("Content to appear/disappear", Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<Float> = spring(stiffness = Spring.StiffnessMediumLow) |
the |
initialAlpha: Float = 0.0f |
the starting alpha of the enter transition, 0f by default |
fadeOut
fun fadeOut(
animationSpec: FiniteAnimationSpec<Float> = spring(stiffness = Spring.StiffnessMediumLow),
targetAlpha: Float = 0.0f
): ExitTransition
This fades out the content of the transition, from full opacity to the specified target alpha (i.e. targetAlpha), using the supplied animationSpec. By default, the content will be faded out to fully transparent (i.e. targetAlpha defaults to 0), and animationSpec uses spring by default.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.requiredHeight import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = fadeIn( // Overwrites the initial value of alpha to 0.4f for fade in, 0 by default initialAlpha = 0.4f ), exit = fadeOut( // Overwrites the default animation with tween animationSpec = tween(durationMillis = 250) ), ) { // Content that needs to appear/disappear goes here: Text("Content to appear/disappear", Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<Float> = spring(stiffness = Spring.StiffnessMediumLow) |
the |
targetAlpha: Float = 0.0f |
the target alpha of the exit transition, 0f by default |
scaleIn
fun scaleIn(
animationSpec: FiniteAnimationSpec<Float> = spring(stiffness = Spring.StiffnessMediumLow),
initialScale: Float = 0.0f,
transformOrigin: TransformOrigin = TransformOrigin.Center
): EnterTransition
This scales the content as it appears, from an initial scale (defined in initialScale) to 1f. transformOrigin defines the pivot point in terms of fraction of the overall size. TransformOrigin.Center by default. scaleIn can be used in combination with any other type of EnterTransition using the plus operator (e.g. scaleIn() + slideInHorizontally())
Note: Scale is applied before slide. This means when using slideIn/slideOut with scaleIn/scaleOut, the amount of scaling needs to be taken into account when sliding.
The scaling will change the visual of the content, but will not affect the layout size. scaleIn can be combined with expandIn/expandHorizontally/expandVertically to coordinate layout size change while scaling. For example:
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.ExitTransition import androidx.compose.animation.expandIn import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut import androidx.compose.animation.shrinkOut import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.unit.dp Column { var showRed by remember { mutableStateOf(true) } var showGreen by remember { mutableStateOf(true) } AnimatedVisibility( visible = showGreen, // By Default, `scaleIn` uses the center as its pivot point. When used with a vertical // expansion from the vertical center, the content will be growing from the center of // the vertically expanding layout. enter = scaleIn() + expandVertically(expandFrom = Alignment.CenterVertically), // By Default, `scaleOut` uses the center as its pivot point. When used with an // ExitTransition that shrinks towards the center, the content will be shrinking both // in terms of scale and layout size towards the center. exit = scaleOut() + shrinkVertically(shrinkTowards = Alignment.CenterVertically), ) { Box( Modifier.size(100.dp) .background(color = Color.Green, shape = RoundedCornerShape(20.dp)) ) } AnimatedVisibility( visible = showRed, // Scale up from the TopLeft by setting TransformOrigin to (0f, 0f), while expanding the // layout size from Top start and fading. This will create a coherent look as if the // scale is impacting the size. enter = scaleIn(transformOrigin = TransformOrigin(0f, 0f)) + fadeIn() + expandIn(expandFrom = Alignment.TopStart), // Scale down from the TopLeft by setting TransformOrigin to (0f, 0f), while shrinking // the layout towards Top start and fading. This will create a coherent look as if the // scale is impacting the layout size. exit = scaleOut(transformOrigin = TransformOrigin(0f, 0f)) + fadeOut() + shrinkOut(shrinkTowards = Alignment.TopStart), ) { Box( Modifier.size(100.dp) .background(color = Color.Red, shape = RoundedCornerShape(20.dp)) ) } }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<Float> = spring(stiffness = Spring.StiffnessMediumLow) |
the animation used for the scale-out, |
initialScale: Float = 0.0f |
the initial scale for the enter transition, 0 by default. |
transformOrigin: TransformOrigin = TransformOrigin.Center |
the pivot point in terms of fraction of the overall size. By default it's |
scaleOut
fun scaleOut(
animationSpec: FiniteAnimationSpec<Float> = spring(stiffness = Spring.StiffnessMediumLow),
targetScale: Float = 0.0f,
transformOrigin: TransformOrigin = TransformOrigin.Center
): ExitTransition
This scales the content of the exit transition, from 1f to the target scale defined in targetScale. transformOrigin defines the pivot point in terms of fraction of the overall size. By default it's TransformOrigin.Center. scaleOut can be used in combination with any other type of ExitTransition using the plus operator (e.g. scaleOut() + fadeOut())
Note: Scale is applied before slide. This means when using slideIn/slideOut with scaleIn/scaleOut, the amount of scaling needs to be taken into account when sliding.
The scaling will change the visual of the content, but will not affect the layout size. scaleOut can be combined with shrinkOut/shrinkHorizontally/shrinkVertically for coordinated layout size change animation. For example:
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.ExitTransition import androidx.compose.animation.expandIn import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut import androidx.compose.animation.shrinkOut import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.unit.dp Column { var showRed by remember { mutableStateOf(true) } var showGreen by remember { mutableStateOf(true) } AnimatedVisibility( visible = showGreen, // By Default, `scaleIn` uses the center as its pivot point. When used with a vertical // expansion from the vertical center, the content will be growing from the center of // the vertically expanding layout. enter = scaleIn() + expandVertically(expandFrom = Alignment.CenterVertically), // By Default, `scaleOut` uses the center as its pivot point. When used with an // ExitTransition that shrinks towards the center, the content will be shrinking both // in terms of scale and layout size towards the center. exit = scaleOut() + shrinkVertically(shrinkTowards = Alignment.CenterVertically), ) { Box( Modifier.size(100.dp) .background(color = Color.Green, shape = RoundedCornerShape(20.dp)) ) } AnimatedVisibility( visible = showRed, // Scale up from the TopLeft by setting TransformOrigin to (0f, 0f), while expanding the // layout size from Top start and fading. This will create a coherent look as if the // scale is impacting the size. enter = scaleIn(transformOrigin = TransformOrigin(0f, 0f)) + fadeIn() + expandIn(expandFrom = Alignment.TopStart), // Scale down from the TopLeft by setting TransformOrigin to (0f, 0f), while shrinking // the layout towards Top start and fading. This will create a coherent look as if the // scale is impacting the layout size. exit = scaleOut(transformOrigin = TransformOrigin(0f, 0f)) + fadeOut() + shrinkOut(shrinkTowards = Alignment.TopStart), ) { Box( Modifier.size(100.dp) .background(color = Color.Red, shape = RoundedCornerShape(20.dp)) ) } }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<Float> = spring(stiffness = Spring.StiffnessMediumLow) |
the animation used for the slide-out, |
targetScale: Float = 0.0f |
the target scale for the exit transition, 0 by default. |
transformOrigin: TransformOrigin = TransformOrigin.Center |
the pivot point in terms of fraction of the overall size. By default it's |
shrinkHorizontally
fun shrinkHorizontally(
animationSpec: FiniteAnimationSpec<IntSize> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold, ),
shrinkTowards: Alignment.Horizontal = Alignment.End,
clip: Boolean = true,
targetWidth: (fullWidth: Int) -> Int = { 0 }
): ExitTransition
This shrinks the clip bounds of the disappearing content horizontally, from the full width to the width returned from targetWidth. shrinkTowards controls the direction of the bounds shrink animation. By default, the clip bounds animates from full width to 0, shrinking towards the end of the content.
Note: shrinkHorizontally animates the bounds of the content. This bounds change will also result in the animation of other layouts that are dependent on this size.
targetWidth is a lambda that takes the full width of the content and returns a target width of the content. This allows not only absolute width, but also a target width that is proportional to the content width.
clip defines whether the content outside of the animated bounds should be clipped. By default, clip is set to true, which only shows content in the animated bounds.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween import androidx.compose.animation.expandHorizontally import androidx.compose.animation.shrinkHorizontally import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.width import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, // Set the start width to 20 (pixels), 0 by default enter = expandHorizontally { 20 }, exit = shrinkHorizontally( // Overwrites the default animation with tween for this shrink animation. animationSpec = tween(), // Shrink towards the end (i.e. right edge for LTR, left edge for RTL). The default // direction for the shrink is towards [Alignment.Start] shrinkTowards = Alignment.End, ) { fullWidth -> // Set the end width for the shrink animation to a quarter of the full width. fullWidth / 4 }, ) { // Content that needs to appear/disappear goes here: Box(Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntSize> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntSize.VisibilityThreshold,
) |
the animation used for the shrinking animation, |
shrinkTowards: Alignment.Horizontal = Alignment.End |
the ending point of the shrinking bounds, |
clip: Boolean = true |
whether the content outside of the animated bounds should be clipped, true by default |
targetWidth: (fullWidth: Int) -> Int = { 0 } |
returns the end width of the shrinking bounds, 0 by default. |
shrinkOut
fun shrinkOut(
animationSpec: FiniteAnimationSpec<IntSize> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold, ),
shrinkTowards: Alignment = Alignment.BottomEnd,
clip: Boolean = true,
targetSize: (fullSize: IntSize) -> IntSize = { IntSize(0, 0) }
): ExitTransition
This shrinks the clip bounds of the disappearing content from the full size to the size returned from targetSize. shrinkTowards controls the direction of the bounds shrink animation. By default, the clip bounds animates from full size to IntSize(0, 0), shrinking towards the the bottom right corner (or bottom left corner in RTL layouts) of the content.
Note: shrinkOut animates the bounds of the content. This bounds change will also result in the animation of other layouts that are dependent on this size.
targetSize is a lambda that takes the full size of the content and returns a target size of the bounds of the content. This allows not only absolute size, but also a target size that is proportional to the content size.
clip defines whether the content outside of the animated bounds should be clipped. By default, clip is set to true, which only shows content in the animated bounds.
For shrinking only horizontally or vertically, consider shrinkHorizontally, shrinkVertically.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.LinearOutSlowInEasing import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.animation.expandIn import androidx.compose.animation.shrinkOut import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible, enter = expandIn( // Overwrites the default spring animation with tween animationSpec = tween(100, easing = LinearOutSlowInEasing), // Overwrites the corner of the content that is first revealed expandFrom = Alignment.BottomStart, ) { // Overwrites the initial size to 50 pixels by 50 pixels IntSize(50, 50) }, exit = shrinkOut( tween(100, easing = FastOutSlowInEasing), // Overwrites the area of the content that the shrink animation will end on. The // following parameters will shrink the content's clip bounds from the full size of // the // content to 1/10 of the width and 1/5 of the height. The shrinking clip bounds // will // always be aligned to the CenterStart of the full-content bounds. shrinkTowards = Alignment.CenterStart, ) { fullSize -> // Overwrites the target size of the shrinking animation. IntSize(fullSize.width / 10, fullSize.height / 5) }, ) { // Content that needs to appear/disappear goes here: Text("Content to appear/disappear", Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntSize> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntSize.VisibilityThreshold,
) |
the animation used for the shrinking animation, |
shrinkTowards: Alignment = Alignment.BottomEnd |
the ending point of the shrinking bounds, |
clip: Boolean = true |
whether the content outside of the animated bounds should be clipped, true by default |
targetSize: (fullSize: IntSize) -> IntSize = { IntSize(0, 0) } |
returns the end size of the shrinking bounds, |
shrinkVertically
fun shrinkVertically(
animationSpec: FiniteAnimationSpec<IntSize> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntSize.VisibilityThreshold, ),
shrinkTowards: Alignment.Vertical = Alignment.Bottom,
clip: Boolean = true,
targetHeight: (fullHeight: Int) -> Int = { 0 }
): ExitTransition
This shrinks the clip bounds of the disappearing content vertically, from the full height to the height returned from targetHeight. shrinkTowards controls the direction of the bounds shrink animation. By default, the clip bounds animates from full height to 0, shrinking towards the bottom of the content.
Note: shrinkVertically animates the bounds of the content. This bounds change will also result in the animation of other layouts that are dependent on this size.
targetHeight is a lambda that takes the full height of the content and returns a target height of the content. This allows not only absolute height, but also a target height that is proportional to the content height.
clip defines whether the content outside of the animated bounds should be clipped. By default, clip is set to true, which only shows content in the animated bounds.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.tween import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.requiredHeight import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible, // Sets the initial height of the content to 20, revealing only the top of the content at // the beginning of the expanding animation. enter = expandVertically(expandFrom = Alignment.Top) { 20 }, // Shrinks the content to half of its full height via an animation. exit = shrinkVertically(animationSpec = tween()) { fullHeight -> fullHeight / 2 }, ) { // Content that needs to appear/disappear goes here: Text("Content to appear/disappear", Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntSize> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntSize.VisibilityThreshold,
) |
the animation used for the shrinking animation, |
shrinkTowards: Alignment.Vertical = Alignment.Bottom |
the ending point of the shrinking bounds, |
clip: Boolean = true |
whether the content outside of the animated bounds should be clipped, true by default |
targetHeight: (fullHeight: Int) -> Int = { 0 } |
returns the end height of the shrinking bounds, 0 by default. |
slideIn
fun slideIn(
animationSpec: FiniteAnimationSpec<IntOffset> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntOffset.VisibilityThreshold, ),
initialOffset: (fullSize: IntSize) -> IntOffset
): EnterTransition
This slides in the content of the transition, from a starting offset defined in initialOffset to IntOffset(0, 0). The direction of the slide can be controlled by configuring the initialOffset. A positive x value means sliding from right to left, whereas a negative x value will slide the content to the right. Similarly positive and negative y values correspond to sliding up and down, respectively.
If the sliding is only desired horizontally or vertically, instead of along both axis, consider using slideInHorizontally or slideInVertically.
initialOffset is a lambda that takes the full size of the content and returns an offset. This allows the offset to be defined proportional to the full size, or as an absolute value.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.LinearOutSlowInEasing import androidx.compose.animation.core.tween import androidx.compose.animation.slideIn import androidx.compose.animation.slideOut import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible, enter = slideIn(tween(100, easing = LinearOutSlowInEasing)) { fullSize -> // Specifies the starting offset of the slide-in to be 1/4 of the width to the // right, // 100 (pixels) below the content position, which results in a simultaneous slide up // and slide left. IntOffset(fullSize.width / 4, 100) }, exit = slideOut(tween(100, easing = FastOutSlowInEasing)) { // The offset can be entirely independent of the size of the content. This specifies // a target offset 180 pixels to the left of the content, and 50 pixels below. This // will // produce a slide-left combined with a slide-down. IntOffset(-180, 50) }, ) { // Content that needs to appear/disappear goes here: Text("Content to appear/disappear", Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntOffset> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntOffset.VisibilityThreshold,
) |
the animation used for the slide-in, |
initialOffset: (fullSize: IntSize) -> IntOffset |
a lambda that takes the full size of the content and returns the initial offset for the slide-in |
slideInHorizontally
fun slideInHorizontally(
animationSpec: FiniteAnimationSpec<IntOffset> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntOffset.VisibilityThreshold, ),
initialOffsetX: (fullWidth: Int) -> Int = { -it / 2 }
): EnterTransition
This slides in the content horizontally, from a starting offset defined in initialOffsetX to 0 pixels. The direction of the slide can be controlled by configuring the initialOffsetX. A positive value means sliding from right to left, whereas a negative value would slide the content from left to right.
initialOffsetX is a lambda that takes the full width of the content and returns an offset. This allows the starting offset to be defined proportional to the full size, or as an absolute value. It defaults to return half of negative width, which would offset the content to the left by half of its width, and slide towards the right.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideIn import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOut import androidx.compose.animation.slideOutHorizontally import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.width import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = slideInHorizontally(animationSpec = tween(durationMillis = 200)) { fullWidth -> // Offsets the content by 1/3 of its width to the left, and slide towards right // Overwrites the default animation with tween for this slide animation. -fullWidth / 3 } + fadeIn( // Overwrites the default animation with tween animationSpec = tween(durationMillis = 200) ), exit = slideOutHorizontally(animationSpec = spring(stiffness = Spring.StiffnessHigh)) { // Overwrites the ending position of the slide-out to 200 (pixels) to the right 200 } + fadeOut(), ) { // Content that needs to appear/disappear goes here: Box(Modifier.fillMaxWidth().requiredHeight(200.dp)) {} }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntOffset> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntOffset.VisibilityThreshold,
) |
the animation used for the slide-in, |
initialOffsetX: (fullWidth: Int) -> Int = { -it / 2 } |
a lambda that takes the full width of the content in pixels and returns the initial offset for the slide-in, by default it returns |
slideInVertically
fun slideInVertically(
animationSpec: FiniteAnimationSpec<IntOffset> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntOffset.VisibilityThreshold, ),
initialOffsetY: (fullHeight: Int) -> Int = { -it / 2 }
): EnterTransition
This slides in the content vertically, from a starting offset defined in initialOffsetY to 0 in pixels. The direction of the slide can be controlled by configuring the initialOffsetY. A positive initial offset means sliding up, whereas a negative value would slide the content down.
initialOffsetY is a lambda that takes the full Height of the content and returns an offset. This allows the starting offset to be defined proportional to the full height, or as an absolute value. It defaults to return half of negative height, which would offset the content up by half of its Height, and slide down.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.expandVertically import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleOut import androidx.compose.animation.shrinkVertically import androidx.compose.animation.slideIn import androidx.compose.animation.slideInVertically import androidx.compose.animation.slideOut import androidx.compose.animation.slideOutVertically import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.requiredHeight import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = slideInVertically( // Start the slide from 40 (pixels) above where the content is supposed to go, to // produce a parallax effect initialOffsetY = { -40 } ) + expandVertically(expandFrom = Alignment.Top) + scaleIn( // Animate scale from 0f to 1f using the top center as the pivot point. transformOrigin = TransformOrigin(0.5f, 0f) ) + fadeIn(initialAlpha = 0.3f), exit = slideOutVertically() + shrinkVertically() + fadeOut() + scaleOut(targetScale = 1.2f), ) { // Content that needs to appear/disappear goes here: Text("Content to appear/disappear", Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntOffset> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntOffset.VisibilityThreshold,
) |
the animation used for the slide-in, |
initialOffsetY: (fullHeight: Int) -> Int = { -it / 2 } |
a lambda that takes the full Height of the content and returns the initial offset for the slide-in, by default it returns |
slideOut
fun slideOut(
animationSpec: FiniteAnimationSpec<IntOffset> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntOffset.VisibilityThreshold, ),
targetOffset: (fullSize: IntSize) -> IntOffset
): ExitTransition
This slides out the content of the transition, from an offset of IntOffset(0, 0) to the target offset defined in targetOffset. The direction of the slide can be controlled by configuring the targetOffset. A positive x value means sliding from left to right, whereas a negative x value would slide the content from right to left. Similarly, positive and negative y values correspond to sliding down and up, respectively.
If the sliding is only desired horizontally or vertically, instead of along both axis, consider using slideOutHorizontally or slideOutVertically.
targetOffset is a lambda that takes the full size of the content and returns an offset. This allows the offset to be defined proportional to the full size, or as an absolute value.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.LinearOutSlowInEasing import androidx.compose.animation.core.tween import androidx.compose.animation.slideIn import androidx.compose.animation.slideOut import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible, enter = slideIn(tween(100, easing = LinearOutSlowInEasing)) { fullSize -> // Specifies the starting offset of the slide-in to be 1/4 of the width to the // right, // 100 (pixels) below the content position, which results in a simultaneous slide up // and slide left. IntOffset(fullSize.width / 4, 100) }, exit = slideOut(tween(100, easing = FastOutSlowInEasing)) { // The offset can be entirely independent of the size of the content. This specifies // a target offset 180 pixels to the left of the content, and 50 pixels below. This // will // produce a slide-left combined with a slide-down. IntOffset(-180, 50) }, ) { // Content that needs to appear/disappear goes here: Text("Content to appear/disappear", Modifier.fillMaxWidth().requiredHeight(200.dp)) }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntOffset> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntOffset.VisibilityThreshold,
) |
the animation used for the slide-out, |
targetOffset: (fullSize: IntSize) -> IntOffset |
a lambda that takes the full size of the content and returns the target offset for the slide-out |
slideOutHorizontally
fun slideOutHorizontally(
animationSpec: FiniteAnimationSpec<IntOffset> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntOffset.VisibilityThreshold, ),
targetOffsetX: (fullWidth: Int) -> Int = { -it / 2 }
): ExitTransition
This slides out the content horizontally, from 0 to a target offset defined in targetOffsetX in pixels. The direction of the slide can be controlled by configuring the targetOffsetX. A positive value means sliding to the right, whereas a negative value would slide the content towards the left.
targetOffsetX is a lambda that takes the full width of the content and returns an offset. This allows the target offset to be defined proportional to the full size, or as an absolute value. It defaults to return half of negative width, which would slide the content to the left by half of its width.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.Spring import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.slideIn import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOut import androidx.compose.animation.slideOutHorizontally import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.requiredHeight import androidx.compose.foundation.layout.width import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } AnimatedVisibility( visible = visible, enter = slideInHorizontally(animationSpec = tween(durationMillis = 200)) { fullWidth -> // Offsets the content by 1/3 of its width to the left, and slide towards right // Overwrites the default animation with tween for this slide animation. -fullWidth / 3 } + fadeIn( // Overwrites the default animation with tween animationSpec = tween(durationMillis = 200) ), exit = slideOutHorizontally(animationSpec = spring(stiffness = Spring.StiffnessHigh)) { // Overwrites the ending position of the slide-out to 200 (pixels) to the right 200 } + fadeOut(), ) { // Content that needs to appear/disappear goes here: Box(Modifier.fillMaxWidth().requiredHeight(200.dp)) {} }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntOffset> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntOffset.VisibilityThreshold,
) |
the animation used for the slide-out, |
targetOffsetX: (fullWidth: Int) -> Int = { -it / 2 } |
a lambda that takes the full width of the content and returns the initial offset for the slide-in, by default it returns |
slideOutVertically
fun slideOutVertically(
animationSpec: FiniteAnimationSpec<IntOffset> = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = IntOffset.VisibilityThreshold, ),
targetOffsetY: (fullHeight: Int) -> Int = { -it / 2 }
): ExitTransition
This slides out the content vertically, from 0 to a target offset defined in targetOffsetY in pixels. The direction of the slide-out can be controlled by configuring the targetOffsetY. A positive target offset means sliding down, whereas a negative value would slide the content up.
targetOffsetY is a lambda that takes the full Height of the content and returns an offset. This allows the target offset to be defined proportional to the full height, or as an absolute value. It defaults to return half of the negative height, which would slide the content up by half of its Height.
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<IntOffset> = spring(
stiffness = Spring.StiffnessMediumLow,
visibilityThreshold = IntOffset.VisibilityThreshold,
) |
the animation used for the slide-out, |
targetOffsetY: (fullHeight: Int) -> Int = { -it / 2 } |
a lambda that takes the full Height of the content and returns the target offset for the slide-out, by default it returns |
unveilIn
@ExperimentalAnimationApi
fun unveilIn(
animationSpec: FiniteAnimationSpec<Color> = spring(stiffness = Spring.StiffnessMediumLow),
initialColor: Color = Color.Black.copy(alpha = 0.5f),
matchParentSize: Boolean = false
): EnterTransition
This animates an unveiling scrim over the content as it enters.
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.togetherWith import androidx.compose.animation.unveilIn import androidx.compose.animation.veilOut import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color var visible by remember { mutableStateOf(true) } Column { Button(onClick = { visible = !visible }) { Text("Toggle") } AnimatedContent( targetState = visible, transitionSpec = { if (targetState) { (slideInHorizontally { it } togetherWith veilOut()).apply { targetContentZIndex = 1f } } else { unveilIn() togetherWith slideOutHorizontally { it } } }, ) { isVisible -> if (isVisible) { Text(modifier = Modifier.fillMaxSize().background(Color.Red), text = "Page 2") } else { Text(modifier = Modifier.fillMaxSize(), text = "Page 1") } } }
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.unveilIn import androidx.compose.animation.veilOut import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } Column(modifier = Modifier.background(Color.White)) { Button(onClick = { visible = !visible }) { Text("Toggle") } AnimatedVisibility( visible = visible, enter = unveilIn(initialColor = Color.White), exit = veilOut(targetColor = Color.White), ) { Box(Modifier.fillMaxSize().padding(30.dp).background(Color.Blue)) { Text("Content") } } }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<Color> = spring(stiffness = Spring.StiffnessMediumLow) |
the animation used for the scrim, |
initialColor: Color = Color.Black.copy(alpha = 0.5f) |
the starting color of the scrim. |
matchParentSize: Boolean = false |
whether the scrim should match the parent size. When |
veilOut
@ExperimentalAnimationApi
fun veilOut(
animationSpec: FiniteAnimationSpec<Color> = spring(stiffness = Spring.StiffnessMediumLow),
targetColor: Color = Color.Black.copy(alpha = 0.5f),
matchParentSize: Boolean = false
): ExitTransition
This animates a veiling scrim over the content as it exits.
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.togetherWith import androidx.compose.animation.unveilIn import androidx.compose.animation.veilOut import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color var visible by remember { mutableStateOf(true) } Column { Button(onClick = { visible = !visible }) { Text("Toggle") } AnimatedContent( targetState = visible, transitionSpec = { if (targetState) { (slideInHorizontally { it } togetherWith veilOut()).apply { targetContentZIndex = 1f } } else { unveilIn() togetherWith slideOutHorizontally { it } } }, ) { isVisible -> if (isVisible) { Text(modifier = Modifier.fillMaxSize().background(Color.Red), text = "Page 2") } else { Text(modifier = Modifier.fillMaxSize(), text = "Page 1") } } }
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.unveilIn import androidx.compose.animation.veilOut import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.material.Button import androidx.compose.material.Text import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp var visible by remember { mutableStateOf(true) } Column(modifier = Modifier.background(Color.White)) { Button(onClick = { visible = !visible }) { Text("Toggle") } AnimatedVisibility( visible = visible, enter = unveilIn(initialColor = Color.White), exit = veilOut(targetColor = Color.White), ) { Box(Modifier.fillMaxSize().padding(30.dp).background(Color.Blue)) { Text("Content") } } }
| Parameters | |
|---|---|
animationSpec: FiniteAnimationSpec<Color> = spring(stiffness = Spring.StiffnessMediumLow) |
the animation used for the scrim, |
targetColor: Color = Color.Black.copy(alpha = 0.5f) |
the target color of the scrim. |
matchParentSize: Boolean = false |
whether the scrim should match the parent size. When |
Extension functions
EnterTransition.togetherWith
infix fun EnterTransition.togetherWith(exit: ExitTransition): ContentTransform
This creates a ContentTransform using the provided EnterTransition and exit, where the enter and exit transition will be running simultaneously. For example:
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.ContentTransform import androidx.compose.animation.SizeTransform import androidx.compose.animation.core.keyframes import androidx.compose.animation.core.tween import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.animation.togetherWith import androidx.compose.ui.unit.IntSize // enum class CartState { Expanded, Collapsed } val transitionSpec: AnimatedContentTransitionScope<CartState>.() -> ContentTransform = { // Fade in with a delay so that it starts after fade out fadeIn(animationSpec = tween(150, delayMillis = 150)) .togetherWith(fadeOut(animationSpec = tween(150))) .using( SizeTransform { initialSize, targetSize -> // Using different SizeTransform for different state change if (CartState.Collapsed isTransitioningTo CartState.Expanded) { keyframes { durationMillis = 500 // Animate to full target width and by 200px in height at 150ms IntSize(targetSize.width, initialSize.height + 200) at 150 } } else { keyframes { durationMillis = 500 // Animate 1/2 the height without changing the width at 150ms. // The width and rest of the height will be animated in the // timeframe between 150ms and duration (i.e. 500ms) IntSize( initialSize.width, (initialSize.height + targetSize.height) / 2, ) at 150 } } } ) }
EnterTransition.with
@ExperimentalAnimationApi
infix fun EnterTransition.with(exit: ExitTransition): ContentTransform
Extension properties
Color.Companion.VectorConverter
val Color.Companion.VectorConverter: (colorSpace: ColorSpace) -> TwoWayConverter<Color, AnimationVector4D>
A lambda that takes a ColorSpace and returns a converter that can both convert a Color to a AnimationVector4D, and convert a AnimationVector4D) back to a Color in the given ColorSpace.