androidx.compose.animation

In this page, you'll find documentation for types, properties, and functions available in the androidx.compose.animation package. For example:

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

AnimatedContentTransitionScope provides functions that are convenient and only applicable in the context of AnimatedContent, such as slideIntoContainer and slideOutOfContainer.

Cmn
AnimatedVisibilityScope

This is the scope for the content of AnimatedVisibility.

Cmn
BoundsTransform

BoundsTransform defines the animation spec used to animate from initial bounds to the target bounds.

Cmn
SharedTransitionScope

SharedTransitionScope provides a coordinator space in which shared elements/ shared bounds (when matched) will transform their bounds from one to another.

Cmn
SharedTransitionScope.OverlayClip

OverlayClip defines a specific clipping that should be applied to a sharedBounds or sharedElement in the overlay.

Cmn
SharedTransitionScope.PlaceholderSize

PlaceholderSize defines the size of the space that was or will be occupied by the exiting or entering sharedElement/sharedBounds.

Cmn
SharedTransitionScope.ResizeMode

There are two different modes to resize child layout of sharedBounds during bounds transform: 1) scaleToBounds and 2) RemeasureToBounds.

Cmn
SharedTransitionScope.SharedContentConfig

SharedContentConfig allows a shared element to be disabled or enabled dynamically through isEnabled property.

Cmn
SizeTransform

SizeTransform defines how to transform from one size to another when the size of the content changes.

Cmn

Classes

AnimatedContentTransitionScope.SlideDirection

SlideDirection defines the direction of the slide in/out for slideIntoContainer and slideOutOfContainer.

Cmn
ContentTransform

ContentTransform defines how the target content (i.e. content associated with target state) enters AnimatedContent and how the initial content disappears.

Cmn
EnterTransition

EnterTransition defines how an AnimatedVisibility Composable appears on screen as it becomes visible.

Cmn
ExitTransition

ExitTransition defines how an AnimatedVisibility Composable disappears on screen as it becomes not visible.

Cmn
SharedTransitionScope.SharedContentState

SharedContentState is designed to allow access of the properties of sharedBounds/sharedElement, such as whether a match of the same key has been found in the SharedTransitionScope, its clipPathInOverlay and parentSharedContentState if there is a parent sharedBounds in the layout tree.

Cmn
SplineBasedFloatDecayAnimationSpec

A native Android fling curve decay.

Cmn

Objects

Annotations

Enums

EnterExitState

EnterExitState contains the three states that are involved in the enter and exit transition of AnimatedVisibility.

Cmn

Composables

AnimatedContent

AnimatedContent is a container that automatically animates its content when targetState changes.

Cmn
AnimatedVisibility

AnimatedVisibility composable animates the appearance and disappearance of its content, as visible value changes.

Cmn
Crossfade

Crossfade allows to switch between two layouts with a crossfade animation.

Cmn
CustomizedLookaheadAnimationVisualDebugging

Allows customizing a particular shared element or animated bounds animation for debugging.

Cmn
LookaheadAnimationVisualDebugging

Allows enabling and customizing shared element and animated bounds animation debugging.

Cmn
SharedTransitionLayout

SharedTransitionLayout creates a layout and a SharedTransitionScope for the child layouts in content.

Cmn
SharedTransitionScope

SharedTransitionScope creates a SharedTransitionScope for the child layouts in content.

Cmn
animateColor

Creates a Color animation that runs infinitely as a part of the given InfiniteTransition.

Cmn
animateColorAsState

Fire-and-forget animation function for Color.

Cmn
defaultDecayAnimationSpec

Create default DecayAnimationSpec representing a default fling curve for a platform.

Cmn
android
rememberSplineBasedDecay
Cmn
android

Modifiers

animateBounds

Modifier to animate layout changes (position and/or size) that occur within a LookaheadScope.

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<ColorAnimationVector4D>

This Animatable function creates a Color value holder that automatically animates its value when the value is changed via animateTo.

Cmn
SizeTransform
SizeTransform(
    clip: Boolean,
    sizeAnimationSpec: (initialSize: IntSize, targetSize: IntSize) -> FiniteAnimationSpec<IntSize>
)

This creates a SizeTransform with the provided clip and sizeAnimationSpec.

Cmn
EnterTransition
expandHorizontally(
    animationSpec: FiniteAnimationSpec<IntSize>,
    expandFrom: Alignment.Horizontal,
    clip: Boolean,
    initialWidth: (fullWidth: Int) -> Int
)

This expands the clip bounds of the appearing content horizontally, from the width returned from initialWidth to the full width.

Cmn
EnterTransition
expandIn(
    animationSpec: FiniteAnimationSpec<IntSize>,
    expandFrom: Alignment,
    clip: Boolean,
    initialSize: (fullSize: IntSize) -> IntSize
)

This expands the clip bounds of the appearing content from the size returned from initialSize to the full size.

Cmn
EnterTransition
expandVertically(
    animationSpec: FiniteAnimationSpec<IntSize>,
    expandFrom: Alignment.Vertical,
    clip: Boolean,
    initialHeight: (fullHeight: Int) -> Int
)

This expands the clip bounds of the appearing content vertically, from the height returned from initialHeight to the full height.

Cmn
EnterTransition
fadeIn(animationSpec: FiniteAnimationSpec<Float>, initialAlpha: Float)

This fades in the content of the transition, from the specified starting alpha (i.e. initialAlpha) to 1f, using the supplied animationSpec.

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. targetAlpha), using the supplied animationSpec.

Cmn
EnterTransition
scaleIn(
    animationSpec: FiniteAnimationSpec<Float>,
    initialScale: Float,
    transformOrigin: TransformOrigin
)

This scales the content as it appears, from an initial scale (defined in initialScale) to 1f.

Cmn
ExitTransition
scaleOut(
    animationSpec: FiniteAnimationSpec<Float>,
    targetScale: Float,
    transformOrigin: TransformOrigin
)

This scales the content of the exit transition, from 1f to the target scale defined in targetScale.

Cmn
ExitTransition
shrinkHorizontally(
    animationSpec: FiniteAnimationSpec<IntSize>,
    shrinkTowards: Alignment.Horizontal,
    clip: Boolean,
    targetWidth: (fullWidth: Int) -> Int
)

This shrinks the clip bounds of the disappearing content horizontally, from the full width to the width returned from targetWidth.

Cmn
ExitTransition
shrinkOut(
    animationSpec: FiniteAnimationSpec<IntSize>,
    shrinkTowards: Alignment,
    clip: Boolean,
    targetSize: (fullSize: IntSize) -> IntSize
)

This shrinks the clip bounds of the disappearing content from the full size to the size returned from targetSize.

Cmn
ExitTransition
shrinkVertically(
    animationSpec: FiniteAnimationSpec<IntSize>,
    shrinkTowards: Alignment.Vertical,
    clip: Boolean,
    targetHeight: (fullHeight: Int) -> Int
)

This shrinks the clip bounds of the disappearing content vertically, from the full height to the height returned from targetHeight.

Cmn
EnterTransition
slideIn(
    animationSpec: FiniteAnimationSpec<IntOffset>,
    initialOffset: (fullSize: IntSize) -> IntOffset
)

This slides in the content of the transition, from a starting offset defined in initialOffset to IntOffset(0, 0).

Cmn
EnterTransition
slideInHorizontally(
    animationSpec: FiniteAnimationSpec<IntOffset>,
    initialOffsetX: (fullWidth: Int) -> Int
)

This slides in the content horizontally, from a starting offset defined in initialOffsetX to 0 pixels.

Cmn
EnterTransition
slideInVertically(
    animationSpec: FiniteAnimationSpec<IntOffset>,
    initialOffsetY: (fullHeight: Int) -> Int
)

This slides in the content vertically, from a starting offset defined in initialOffsetY to 0 in pixels.

Cmn
ExitTransition
slideOut(
    animationSpec: FiniteAnimationSpec<IntOffset>,
    targetOffset: (fullSize: IntSize) -> IntOffset
)

This slides out the content of the transition, from an offset of IntOffset(0, 0) to the target offset defined in targetOffset.

Cmn
ExitTransition
slideOutHorizontally(
    animationSpec: FiniteAnimationSpec<IntOffset>,
    targetOffsetX: (fullWidth: Int) -> Int
)

This slides out the content horizontally, from 0 to a target offset defined in targetOffsetX in pixels.

Cmn
ExitTransition
slideOutVertically(
    animationSpec: FiniteAnimationSpec<IntOffset>,
    targetOffsetY: (fullHeight: Int) -> Int
)

This slides out the content vertically, from 0 to a target offset defined in targetOffsetY in pixels.

Cmn
DecayAnimationSpec<T>
<T : Any?> splineBasedDecay(density: Density)
Cmn
EnterTransition
@ExperimentalAnimationApi
unveilIn(
    animationSpec: FiniteAnimationSpec<Color>,
    initialColor: Color,
    matchParentSize: Boolean
)

This animates an unveiling scrim over the content as it enters.

Cmn
ExitTransition
@ExperimentalAnimationApi
veilOut(
    animationSpec: FiniteAnimationSpec<Color>,
    targetColor: Color,
    matchParentSize: Boolean
)

This animates a veiling scrim over the content as it exits.

Cmn

Extension functions summary

infix ContentTransform

This creates a ContentTransform using the provided EnterTransition and exit, where the enter and exit transition will be running simultaneously.

Cmn
infix ContentTransform

This function is deprecated. Infix fun EnterTransition.with(ExitTransition) has been renamed to togetherWith

Cmn

Extension properties summary

(colorSpace: ColorSpace) -> TwoWayConverter<ColorAnimationVector4D>

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.

Cmn

Top-level functions

Animatable

@RememberInComposition
fun Animatable(initialValue: Color): Animatable<ColorAnimationVector4D>

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 Animatable

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, spring by default.

expandFrom: Alignment.Horizontal = Alignment.End

the starting point of the expanding bounds, Alignment.End by default.

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, spring by default.

expandFrom: Alignment = Alignment.BottomEnd

the starting point of the expanding bounds, Alignment.BottomEnd by default.

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 IntSize(0, 0) by default.

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, spring by default.

expandFrom: Alignment.Vertical = Alignment.Bottom

the starting point of the expanding bounds, Alignment.Bottom by default.

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.

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 FiniteAnimationSpec for this animation, spring by default

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 FiniteAnimationSpec for this animation, spring by default

targetAlpha: Float = 0.0f

the target alpha of the exit transition, 0f by default

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, spring by default.

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 TransformOrigin.Center.

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, spring by default.

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 TransformOrigin.Center.

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, spring by default.

shrinkTowards: Alignment.Horizontal = Alignment.End

the ending point of the shrinking bounds, Alignment.End by default.

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, spring by default.

shrinkTowards: Alignment = Alignment.BottomEnd

the ending point of the shrinking bounds, Alignment.BottomEnd by default.

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, IntSize(0, 0) by default.

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, spring by default.

shrinkTowards: Alignment.Vertical = Alignment.Bottom

the ending point of the shrinking bounds, Alignment.Bottom by default.

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, spring by default.

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, spring by default.

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 -fullWidth/2

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, spring by default.

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 -fullHeight/2

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, spring by default.

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, spring by default.

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 fullWidth/2

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, spring by default.

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 fullHeight/2

splineBasedDecay

fun <T : Any?> splineBasedDecay(density: Density): DecayAnimationSpec<T>

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, spring by default.

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 matchParentSize is true, the veil is applied independently from all other transforms and matches the parent size. When matchParentSize is false, the veil is applied first and thus is affected by other transforms. Note: The veil may be clipped if a clip modifier is used on the same layout as the EnterTransition, even when matchParentSize is true.

@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, spring by default.

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 matchParentSize is true, the veil is applied independently from all other transforms and matches the parent size. When matchParentSize is false, the veil is applied first and thus is affected by other transforms. Note: The veil may be clipped if a clip modifier is used on the same layout as the ExitTransition, even when matchParentSize is true.

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<ColorAnimationVector4D>

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.