Jetpack Compose如何等待动画结束?

10

我使用了 AnimatedVisibility(slideInVertically/SlideOut) 实现了简单的动画效果。 当我按下 "nextScreenButton" 按钮时,通过 navController 进行新的导航。 过渡是立即完成的,所以没有时间进行退出动画。 如何等待动画结束?

我可以为动画时间设置一些延迟,但这不是一个好的方法。

代码:

      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.

enter image description here

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

导航宿主:


    @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

   

4个回答

15

这是实现此目的的主要思路:

   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
    }

}

语法已更改:val animVisibleState = remember { MutableTransitionState(false).apply { targetState = true } } - lenooh

4

回答您的问题:"如何等待动画结束"。

只需检查转换目标状态是否与转换当前状态相同即可。如果相同,则动画已经结束。

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.

         }

          
    }

这也适用于其他动画,例如AnimatedContent等等


1
这对我来说无法检测动画何时从可见到不可见的过渡完成。currentState始终保持在Visible状态,而targetState则为PostExit。我尝试使用transition.isRunning进行测试,结果有效。 - realh

2
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} 将在每次重新组合时应用此操作,因此LaunchedEffect可能是一种解决方案,还有更好的方法来处理nextButtonPressionState。

2
在Navigation 2.4.0-alpha05中,Crossfade被引入作为导航的默认转换。通过Navigation 2.4.0-alpha06的最新版本,您可以通过Accompanist添加自定义转换。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接