# DeferredAnimatedContent

Common/AllAndroid/JVM

## Functions summary

|---|---|---|
| `https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` | `@https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable <S : https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-any/index.html?> https://developer.android.com/reference/kotlin/androidx/compose/animation/core/DeferredTransition<S>.https://developer.android.com/reference/kotlin/androidx/compose/animation/DeferredAnimatedContent.composable#(androidx.compose.animation.core.DeferredTransition).DeferredAnimatedContent(androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Function1,kotlin.Function2)( modifier: https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier, transitionSpec: https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContentTransitionScope<S>.() -> https://developer.android.com/reference/kotlin/androidx/compose/animation/ContentTransform, contentAlignment: https://developer.android.com/reference/kotlin/androidx/compose/ui/Alignment, contentKey: (targetState) -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-any/index.html?, mutableTransformSpec: https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContentTransitionScope<S>.() -> https://developer.android.com/reference/kotlin/androidx/compose/animation/MutableContentTransform?, content: @https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContentScope.(targetState) -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html )` `https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContent.composable#AnimatedContent(kotlin.Any,androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.String,kotlin.Function1,kotlin.Function2)` is a container that automatically animates its content when `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/Transition#targetState()` changes. | Cmn |

## Functions

### DeferredTransition.DeferredAnimatedContent

Cmn Artifact: [androidx.compose.animation:animation](https://developer.android.com/jetpack/androidx/releases/compose-animation) [View Source](https://cs.android.com/search?q=file:androidx/compose/animation/AnimatedContent.kt+function:DeferredAnimatedContent)

```
@Composable
fun <S : Any?> DeferredTransition<S>.DeferredAnimatedContent(
    modifier: Modifier = Modifier,
    transitionSpec: AnimatedContentTransitionScope<S>.() -> ContentTransform = {
        AnimatedContentDefaults.ContentTransform
    },
    contentAlignment: Alignment = Alignment.TopStart,
    contentKey: (targetState) -> Any? = { it },
    mutableTransformSpec: AnimatedContentTransitionScope<S>.() -> MutableContentTransform? = {
        null
    },
    content: @Composable AnimatedContentScope.(targetState) -> Unit
): Unit
```

`https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContent.composable#AnimatedContent(kotlin.Any,androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.String,kotlin.Function1,kotlin.Function2)` is a container that automatically animates its content when `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/Transition#targetState()` changes. Its `https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#(androidx.compose.animation.core.DeferredTransition).DeferredAnimatedContent(androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Function1,kotlin.Function2)` for different target states is defined in a mapping between a target state and a composable function.

**IMPORTANT** : The targetState parameter for the `https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#(androidx.compose.animation.core.DeferredTransition).DeferredAnimatedContent(androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Function1,kotlin.Function2)` lambda should *always* be taken into account in deciding what composable function to return as the content for that state. This is critical to ensure a successful lookup of all the incoming and outgoing content during content transform.

When `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/Transition#targetState()` changes, content for both new and previous targetState will be looked up through the `https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#(androidx.compose.animation.core.DeferredTransition).DeferredAnimatedContent(androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Function1,kotlin.Function2)` lambda. They will go through a `https://developer.android.com/reference/kotlin/androidx/compose/animation/ContentTransform` so that the new target content can be animated in while the initial content animates out. Meanwhile the container will animate its size as needed to accommodate the new content, unless `https://developer.android.com/reference/kotlin/androidx/compose/animation/SizeTransform` is set to `null`. Once the `https://developer.android.com/reference/kotlin/androidx/compose/animation/ContentTransform` is finished, the outgoing content will be disposed.

If `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/Transition#targetState()` is expected to mutate frequently and not all mutations should be treated as target state change, consider defining a mapping between `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/Transition#targetState()` and a key in `https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#(androidx.compose.animation.core.DeferredTransition).DeferredAnimatedContent(androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Function1,kotlin.Function2)`. As a result, transitions will be triggered when the resulting key changes. In other words, there will be no animation when switching between `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/Transition#targetState()`s that share the same key. By default, the key will be the same as the targetState object.

```kotlin
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.DeferredAnimatedContent
import androidx.compose.animation.MutableContentTransform
import androidx.compose.animation.core.DeferredTransitionState
import androidx.compose.animation.core.rememberDeferredTransition
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.material.Text
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableIntStateOf
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.IntOffset
import androidx.compose.ui.unit.dp

// In a real app, these states would be driven by a gesture handler like PredictiveBackHandler
val targetScreen by remember { mutableIntStateOf(0) }
val isBackGestureInProgress by remember { mutableStateOf(false) }
val swipeOffset by remember { mutableStateOf(IntOffset.Zero) }

val transitionState = remember { DeferredTransitionState(targetScreen) }
val transition = rememberDeferredTransition(transitionState)
LaunchedEffect(isBackGestureInProgress, targetScreen) {
    if (isBackGestureInProgress) {
        transitionState.defer(targetScreen)
    } else {
        transitionState.animateTo(targetScreen)
    }
}

transition.DeferredAnimatedContent(
    transitionSpec = { slideInHorizontally { it } togetherWith slideOutHorizontally { -it } },
    mutableTransformSpec = {
        MutableContentTransform {
            if (isBackGestureInProgress && targetScreen < transitionState.targetState) {
                // Shift the entering and exiting screens based on swipe offset
                targetContentTransform { offset = swipeOffset }
                initialContentTransform {
                    offset = swipeOffset.copy(swipeOffset.x / 2, swipeOffset.y / 2)
                }
            }
        }
    },
) { screen ->
    Box(Modifier.size(200.dp).background(if (screen % 2 == 0) Color.Blue else Color.Green)) {
        Text("Screen $screen")
    }
}
```

```kotlin
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.core.animateDp
import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp

@Composable
fun CollapsedCart() {
    /* Some content here */
}

@Composable
fun ExpandedCart() {
    /* Some content here */
}

// enum class CartState { Expanded, Collapsed }
var cartState by remember { mutableStateOf(CartState.Collapsed) }
// Creates a transition here to animate the corner shape and content.
val cartOpenTransition = updateTransition(cartState, "CartOpenTransition")
val cornerSize by
    cartOpenTransition.animateDp(
        label = "cartCornerSize",
        transitionSpec = {
            when {
                CartState.Expanded isTransitioningTo CartState.Collapsed ->
                    tween(durationMillis = 433, delayMillis = 67)
                else -> tween(durationMillis = 150)
            }
        },
    ) {
        if (it == CartState.Expanded) 0.dp else 24.dp
    }

Surface(
    Modifier.shadow(8.dp, CutCornerShape(topStart = cornerSize))
        .clip(CutCornerShape(topStart = cornerSize)),
    color = Color(0xfffff0ea),
) {
    // Creates an AnimatedContent using the transition. This AnimatedContent will
    // derive its target state from cartOpenTransition.targetState. All the animations
    // created inside of AnimatedContent for size change, enter/exit will be added to the
    // Transition.
    cartOpenTransition.AnimatedContent(
        transitionSpec = {
            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
                            }
                        }
                    }
                )
                .apply {
                    targetContentZIndex =
                        when (targetState) {
                            // This defines a relationship along z-axis during the momentary
                            // overlap as both incoming and outgoing content is on screen. This
                            // fixed zOrder will ensure that collapsed content will always be on
                            // top of the expanded content - it will come in on top, and
                            // disappear over the expanded content as well.
                            CartState.Expanded -> 1f
                            CartState.Collapsed -> 2f
                        }
                }
        }
    ) {
        // This defines the mapping from state to composable. It's critical to use the state
        // parameter (i.e. `it`) that is passed into this block of code to ensure correct
        // content lookup.
        when (it) {
            CartState.Expanded -> ExpandedCart()
            CartState.Collapsed -> CollapsedCart()
        }
    }
}
```

| Parameters |
|---|---|
| `modifier: https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier = Modifier` | is applied to the Layout created by `https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContent.composable#AnimatedContent(kotlin.Any,androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.String,kotlin.Function1,kotlin.Function2)`, which houses all the animating contents. |
| `transitionSpec: https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContentTransitionScope<S>.() -> https://developer.android.com/reference/kotlin/androidx/compose/animation/ContentTransform = { AnimatedContentDefaults.ContentTransform }` | specifies the enter/exit animations, as well as size animation (if applicable). By default, a `https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#fadeIn(androidx.compose.animation.core.FiniteAnimationSpec,kotlin.Float)` and `https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#scaleIn(androidx.compose.animation.core.FiniteAnimationSpec,kotlin.Float,androidx.compose.ui.graphics.TransformOrigin)` will be used for the entering content, and `https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#fadeOut(androidx.compose.animation.core.FiniteAnimationSpec,kotlin.Float)` for the exiting content. The `https://developer.android.com/reference/kotlin/androidx/compose/animation/ContentTransform` returned by `https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#(androidx.compose.animation.core.DeferredTransition).DeferredAnimatedContent(androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Function1,kotlin.Function2)` can be created using `https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#(androidx.compose.animation.EnterTransition).togetherWith(androidx.compose.animation.ExitTransition)` with `https://developer.android.com/reference/kotlin/androidx/compose/animation/EnterTransition` and `https://developer.android.com/reference/kotlin/androidx/compose/animation/ExitTransition`. |
| `contentAlignment: https://developer.android.com/reference/kotlin/androidx/compose/ui/Alignment = Alignment.TopStart` | specifies the alignment of the animated content. By default, it'll be aligned to the top start of the container. |
| `contentKey: (targetState) -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-any/index.html? = { it }` | A key to identify the content. |
| `mutableTransformSpec: https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContentTransitionScope<S>.() -> https://developer.android.com/reference/kotlin/androidx/compose/animation/MutableContentTransform? = { null }` | A specification to control an optional manual transformation during the deferred phase (e.g., for predictive back gestures) before the main transition begins. This is only active if the `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/Transition` was created using `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/rememberDeferredTransition.composable#rememberDeferredTransition(androidx.compose.animation.core.DeferredTransitionState,kotlin.String)` with `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/DeferredTransitionState`. By default, this returns `null`, meaning no manual transformations are applied. **Lifecycle:** The deferred phase starts when `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/DeferredTransitionState#defer(kotlin.Any)` is called. It ends and the automatic transition begins when `https://developer.android.com/reference/kotlin/androidx/compose/animation/core/DeferredTransitionState#animateTo(kotlin.Any)` is called. **Transformations:** During this phase, you can manually manipulate the entering and exiting content's transformations (via `https://developer.android.com/reference/kotlin/androidx/compose/animation/MutableContentTransform`). Properties that are not manually set default to the transition's initial values during the deferred phase. **Handoff:** Once the transition starts, the manually applied transformations are seamlessly handed off to the configured `https://developer.android.com/reference/kotlin/androidx/compose/animation/package-summary#(androidx.compose.animation.core.DeferredTransition).DeferredAnimatedContent(androidx.compose.ui.Modifier,kotlin.Function1,androidx.compose.ui.Alignment,kotlin.Function1,kotlin.Function1,kotlin.Function2)`. For exiting content, a "sustain unless specified" policy is applied: if an exit transition (e.g. `fadeOut`) is specified, the hand-off will animate towards the target value of that transition. However, if no exit transition is specified for a given property (e.g. `slideOut` is missing), that property will sustain its last manual value until the entire transition completes. *Note:* While in the deferred phase, entering content remains in the `https://developer.android.com/reference/kotlin/androidx/compose/animation/EnterExitState#PreEnter` state, and exiting content remains in the `https://developer.android.com/reference/kotlin/androidx/compose/animation/EnterExitState#Visible` state. |
| `content: @https://developer.android.com/reference/kotlin/androidx/compose/runtime/Composable https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContentScope.(targetState) -> https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/-unit/index.html` | The composable function to render the content for a given state. |

| See also |
|---|---|
| `https://developer.android.com/reference/kotlin/androidx/compose/animation/ContentTransform` |   |
| `https://developer.android.com/reference/kotlin/androidx/compose/animation/AnimatedContentScope` |   |