Reputation: 757
I have simple animation by AnimatedVisibility (slideInVertically/SlideOut). When i press "nextScreenButton" i make new navigate by navController. The transition is done instantly, so no time for exit animation. How to make waiting until animations ends
I can enter some delay for animation time, but its not good way.
Code:
Scaffold() {
AnimatedVisibility(
//Boolean State for open animation
OpenChooseProfilePageAnim.value,
initiallyVisible= false,
enter = slideInVertically(
initialOffsetY = { fullHeight -> fullHeight },
animationSpec = tween(
durationMillis = 3000,
easing = LinearOutSlowInEasing
)
),
exit = slideOutVertically(
targetOffsetY = { fullHeight -> fullHeight },
animationSpec = tween(
durationMillis = 3000,
easing = LinearOutSlowInEasing
)
)
) {
ConstraintLayout() {
Card() {
Column() {
//Some other Composable items
//Composable button
NextScreenButton() {
//calling navigation here
}
}
}
}
}
}
Ty for help.
NextScreenButton code:
fun navigateToMainListPage(navController: NavController) {
//change State of visibility for "AnimatedVisibility"
AnimationsState.OpenChooseProfilePageAnim.value = false
//navigate to another route in NavHost
navController.navigate(ROUTE_MAIN_LIST)
}
NavHost:
@Composable
fun LoginGroupNavigation(startDestination: String) {
val navController = rememberNavController()
NavHost(navController, startDestination = startDestination) {
composable(LoginScreens.LoginScreen.route) {
LoginMainPage(navController)
}
composable(LoginScreens.EnteringPhoneNumScreen.route,
arguments = listOf(navArgument("title") { type = NavType.StringType },
)) {
val title = it.arguments?.getString("title") ?: ""
EnterPhoneNumberForSmsPage(
navController = navController,
title
)
}
//more composable screens
Upvotes: 13
Views: 21504
Reputation: 101
This worked for me.
val visibilityTransition = remember {
MutableTransitionState(false)
}.apply {
targetState = true
}
LaunchedEffect(Unit) {
snapshotFlow {
Pair(visibilityTransition.currentState, visibilityTransition.targetState)
}.collectLatest { (curr, target) ->
if(!curr && !target) {
onDismiss.invoke()
}
}
}
Upvotes: 1
Reputation: 13525
to answer your question: "how to wait for animation ends".
just check if the transition.targetState is the same as transition.currentState. if it is the same, then the animation have ended.
AnimatedVisibility(
initiallyVisible= ...,
enter = ...,
exit = ...
) {
...<your layout>
//to detect if your animation have completed just check the following
if (this.transition.currentState == this.transition.targetState){
//Animation is completed when current state is the same as target state.
//you can call whatever you like here -> e.g. start music, show toasts, enable buttons, etc
callback.invoke() //we invoke a callback as an example.
}
}
this will also work for other animations like AnimatedContent, etc
Upvotes: 5
Reputation: 51
val animVisibleState = remember { MutableTransitionState(false) }
val nextButtonPressState = remember { mutableStateOf(false) }
LaunchedEffect(key1 = true) {
animVisibleState.targetState = true
}
if ( !animVisibleState.targetState &&
!animVisibleState.currentState &&
nextButtonPressState.value
) {
navController.navigate(ROUTE_MAIN_LIST)
}
AnimatedVisibility(
visibleState = animVisibleState,
enter = fadeIn(),
exit = fadeOut()
) {
NextButton() {
nextButtonPressState.value = true
}
}
.apply {animVisibleState.target = true} at the declaration of the variable will apply this on every recompositions so LaunchedEffect can be a solution, there also much better way to handle the nextButtonPressionState
Upvotes: 2
Reputation: 2365
Crossfade was introduced as the default transition for navigation in Navigation 2.4.0-alpha05. With the latest release of Navigation 2.4.0-alpha06, you can add custom transitions via Accompanist
Upvotes: 2
Reputation: 335
Here is the main idea to do this:
val animVisibleState = remember { MutableTransitionState(false) }
.apply { targetState = true }
//Note: Once the exit transition is finished,
//the content composable will be removed from the tree,
//and disposed.
//Both currentState and targetState will be false for
//visibleState.
if (!animVisibleState.targetState &&
!animVisibleState.currentState
) {
//navigate to another route in NavHost
navController.navigate(ROUTE_MAIN_LIST)
return
}
AnimatedVisibility(
visibleState = animVisibleState,
enter = fadeIn(
animationSpec = tween(durationMillis = 200)
),
exit = fadeOut(
animationSpec = tween(durationMillis = 200)
)
) {
NextButton() {
//start exit animation
animVisibleState.targetState = false
}
}
Upvotes: 17