AnimatedContent is a container that automatically animates its content when Transition.targetState changes.
DeferredAnimatedContentSample
@OptIn(ExperimentalDeferredTransitionApi::class)
@Composable
fun DeferredAnimatedContentSample() {
// 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 = rememberTransition(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")
}
}
}
TransitionExtensionAnimatedContentSample
@Composable
fun TransitionExtensionAnimatedContentSample() {
@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()
}
}
}
}