Compose Unstyled 2.0 is out! Check the official announcement blog ->
Composable Function

DeferredAnimatedVisibility

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))
    }
}

Last updated: