ExitTransition.Companion

object ExitTransition.Companion


Summary

Public properties

ExitTransition

This can be used when no built-in ExitTransition (i.e.

Public properties

None

val NoneExitTransition

This can be used when no built-in ExitTransition (i.e. fade/slide, etc) is desired for the AnimatedVisibility, but rather the children are defining their own exit animation using the Transition scope.

Note: If None is used, and nothing is animating in the Transition scope that AnimatedVisibility provided, the content will be removed from AnimatedVisibility right away.

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.FloatingActionButton
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer

@OptIn(ExperimentalAnimationApi::class)
@Composable
fun AnimatedVisibilityScope.Item(
    modifier: Modifier,
    backgroundColor: Color
) {
    // Creates a custom enter/exit animation for scale property.
    val scale by transition.animateFloat { enterExitState ->
        // Enter transition will be animating the scale from 0.9f to 1.0f
        // (i.e. PreEnter -> Visible). Exit transition will be from 1.0f to
        // 0.5f (i.e. Visible -> PostExit)
        when (enterExitState) {
            EnterExitState.PreEnter -> 0.9f
            EnterExitState.Visible -> 1.0f
            EnterExitState.PostExit -> 0.5f
        }
    }

    // Since we defined `Item` as an extension function on AnimatedVisibilityScope, we can use
    // the `animateEnterExit` modifier to produce an enter/exit animation for it. This will
    // run simultaneously with the `AnimatedVisibility`'s enter/exit.
    Box(
        modifier.fillMaxWidth().padding(5.dp).animateEnterExit(
            // Slide in from below,
            enter = slideInVertically(initialOffsetY = { it }),
            // No slide on the way out. So the exit animation will be scale (from the custom
            // scale animation defined above) and fade (from AnimatedVisibility)
            exit = ExitTransition.None
        ).graphicsLayer {
            scaleX = scale
            scaleY = scale
        }.clip(RoundedCornerShape(20.dp)).background(backgroundColor).fillMaxSize()
    ) {
        // Content of the item goes here...
    }
}

@OptIn(ExperimentalAnimationApi::class, ExperimentalTransitionApi::class)
@Composable
fun AnimateMainContent(mainContentVisible: MutableTransitionState<Boolean>) {
    Box {
        // Use the `MutableTransitionState<Boolean>` to specify whether AnimatedVisibility
        // should be visible. This will also allow AnimatedVisibility animation states to be
        // observed externally.
        AnimatedVisibility(
            visibleState = mainContentVisible,
            modifier = Modifier.fillMaxSize(),
            enter = fadeIn(),
            exit = fadeOut()
        ) {
            Box {
                Column(Modifier.fillMaxSize()) {
                    // We have created `Item`s below as extension functions on
                    // AnimatedVisibilityScope in this example. So they can define their own
                    // enter/exit to run alongside the enter/exit defined in AnimatedVisibility.
                    Item(Modifier.weight(1f), backgroundColor = Color(0xffff6f69))
                    Item(Modifier.weight(1f), backgroundColor = Color(0xffffcc5c))
                }
                // This FAB will be simply fading in/out as specified by the AnimatedVisibility
                FloatingActionButton(
                    onClick = {},
                    modifier = Modifier.align(Alignment.BottomEnd).padding(20.dp),
                    backgroundColor = MaterialTheme.colors.primary
                ) { Icon(Icons.Default.Favorite, contentDescription = null) }
            }
        }

        // Here we can get a signal for when the Enter/Exit animation of the content above
        // has finished by inspecting the MutableTransitionState passed to the
        // AnimatedVisibility. This allows sequential animation after the enter/exit.
        AnimatedVisibility(
            // Once the main content is visible (i.e. targetState == true), and no pending
            // animations. We will start another enter animation sequentially.
            visible = mainContentVisible.targetState && mainContentVisible.isIdle,
            modifier = Modifier.align(Alignment.Center),
            enter = expandVertically(),
            exit = fadeOut(animationSpec = tween(50))
        ) {
            Text("Transition Finished")
        }
    }
}