DeferredAnimatedVisibility
Functions summary
Unit |
@ExperimentalDeferredTransitionApi
|
Cmn
|
Functions
DeferredTransition.DeferredAnimatedVisibility
@ExperimentalDeferredTransitionApi
@Composable
fun <T : Any?> DeferredTransition<T>.DeferredAnimatedVisibility(
visible: (T) -> Boolean,
modifier: Modifier = Modifier,
enter: EnterTransition = fadeIn() + expandIn(),
exit: ExitTransition = shrinkOut() + fadeOut(),
mutableTransform: MutableTransform? = null,
content: @Composable AnimatedVisibilityScope.() -> Unit
): Unit
AnimatedVisibility can be used to animate the appearance and disappearance of its content as the Transition state changes.
visible defines whether the content should be visible based on transition state T.
modifier modifier for the Layout created to contain the content
enter EnterTransition(s) used for the appearing animation, fading in while expanding vertically by default
exit ExitTransition(s) used for the disappearing animation, fading out while shrinking vertically by default
mutableTransform A block to control the visual transformations during the deferred phase (e.g., for predictive back gestures) before the main transition begins. This is only active if the Transition was created using rememberTransition with DeferredTransitionState. By default, this is null, meaning no manual transformations are applied. This phase starts when DeferredTransitionState.defer is called and ends when DeferredTransitionState.animateTo is called to start the automatic transition. During this phase, you can manually manipulate the content's transformations (like TransformScope.alpha and TransformScope.scale). These transformations are applied on top of the transition's initial state. Once the transition starts, the manually applied transformations are seamlessly handed off to the configured enter and exit transitions. 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. While in the deferred phase, entering content remains in the EnterExitState.PreEnter state, and exiting content remains in the EnterExitState.Visible state.
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.DeferredAnimatedVisibility import androidx.compose.animation.MutableTransform import androidx.compose.animation.core.DeferredTransitionState import androidx.compose.animation.core.rememberTransition import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.runtime.LaunchedEffect 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 var visible by remember { mutableStateOf(true) } var isBackGestureInProgress by remember { mutableStateOf(false) } var swipeOffset by remember { mutableStateOf(IntOffset.Zero) } val transitionState = remember { DeferredTransitionState(visible) } val transition = rememberTransition(transitionState) LaunchedEffect(isBackGestureInProgress, visible) { if (isBackGestureInProgress) { transitionState.defer(visible) } else { transitionState.animateTo(visible) } } transition.DeferredAnimatedVisibility( visible = { it }, mutableTransform = MutableTransform { fullSize -> if (isBackGestureInProgress) { val progressX = (swipeOffset.x.toFloat() / fullSize.width).coerceIn(0f, 1f) // Shrink the content down to 80% as the user swipes scale = 1f - (progressX * 0.2f) // Slide the content along the swipe offset = swipeOffset } }, ) { Box(Modifier.size(200.dp).background(Color.Red)) }
content Content to appear or disappear based on the visibility derived from the Transition.targetState and the provided visible lambda
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.animateColor import androidx.compose.animation.core.animateDp import androidx.compose.animation.core.tween import androidx.compose.animation.core.updateTransition import androidx.compose.animation.expandVertically import androidx.compose.animation.shrinkVertically import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.runtime.Composable 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.unit.dp @Composable fun ItemMainContent() { Row(Modifier.height(100.dp).fillMaxWidth(), Arrangement.SpaceEvenly) { Box( Modifier.size(60.dp) .align(Alignment.CenterVertically) .background(Color(0xffcdb7f6), CircleShape) ) Column(Modifier.align(Alignment.CenterVertically)) { Box(Modifier.height(30.dp).width(300.dp).padding(5.dp).background(Color.LightGray)) Box(Modifier.height(30.dp).width(300.dp).padding(5.dp).background(Color.LightGray)) } } } @OptIn(ExperimentalAnimationApi::class) @Composable fun SelectableItem() { // This sample animates a number of properties, including AnimatedVisibility, as a part of // the Transition going between selected and unselected. Box(Modifier.padding(15.dp)) { var selected by remember { mutableStateOf(false) } // Creates a transition to animate visual changes when `selected` is changed. val selectionTransition = updateTransition(selected) // Animates the border color as a part of the transition val borderColor by selectionTransition.animateColor { isSelected -> if (isSelected) Color(0xff03a9f4) else Color.White } // Animates the background color when selected state changes val contentBackground by selectionTransition.animateColor { isSelected -> if (isSelected) Color(0xffdbf0fe) else Color.White } // Animates elevation as a part of the transition val elevation by selectionTransition.animateDp { isSelected -> if (isSelected) 10.dp else 2.dp } Surface( shape = RoundedCornerShape(10.dp), border = BorderStroke(2.dp, borderColor), modifier = Modifier.clickable { selected = !selected }, color = contentBackground, elevation = elevation, ) { Column(Modifier.fillMaxWidth()) { ItemMainContent() // Creates an AnimatedVisibility as a part of the transition, so that when // selected it's visible. This will hoist all the animations that are internal // to AnimatedVisibility (i.e. fade, slide, etc) to the transition. As a result, // `selectionTransition` will not finish until all the animations in // AnimatedVisibility as well as animations added directly to it have finished. selectionTransition.AnimatedVisibility( visible = { it }, enter = expandVertically(), exit = shrinkVertically(), ) { Box(Modifier.fillMaxWidth().padding(10.dp)) { Text( "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed" + " eiusmod tempor incididunt labore et dolore magna aliqua. " + "Ut enim ad minim veniam, quis nostrud exercitation ullamco " + "laboris nisi ut aliquip ex ea commodo consequat. Duis aute " + "irure dolor." ) } } } } } }