AnimatedVisibility can be used to animate the appearance and disappearance of its content as the Transition state changes.
AddAnimatedVisibilityToGenericTransitionSample
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun AddAnimatedVisibilityToGenericTransitionSample() {
@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."
)
}
}
}
}
}
}
}
DeferredAnimatedVisibilitySample
@OptIn(ExperimentalDeferredTransitionApi::class)
@Composable
fun DeferredAnimatedVisibilitySample() {
// 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))
}
}