Android Compose导航:过渡动画无法获取导航参数问题排查
在使用Compose Navigation时,配置页面的enterTransition和exitTransition时,尝试通过initialState.arguments获取导航参数x、y,结果值为null;但在Composable的lambda代码块中通过it.arguments访问这些参数时,却能得到正确的值。
复现代码
composable( route = NavigationRoute.PreviewImage.route, deepLinks = listOf(navDeepLink { uriPattern = "suntuk://preview/{id}/{type}/{x}/{y}" }), arguments = listOf( navArgument("id") { type = NavType.StringType }, navArgument("type") { type = NavType.IntType }, navArgument("x") { type = NavType.FloatType }, navArgument("y") { type = NavType.FloatType } ), enterTransition = { val offsetX = initialState.arguments?.getFloat("x") ?: 0f val offsetY = initialState.arguments?.getFloat("y") ?: 0f scaleIn( animationSpec = tween(durationMillis = 5000), transformOrigin = TransformOrigin( offsetX, offsetY ) ) }, exitTransition = { val offsetX = initialState.arguments?.getFloat("x") ?: 0f val offsetY = initialState.arguments?.getFloat("y") ?: 0f Timber.i("Offset: $offsetX, $offsetY") scaleOut( animationSpec = tween(durationMillis = 5000), transformOrigin = TransformOrigin( offsetX, offsetY ) ) } ) { val id = it.arguments?.getString("id") ?: "" val type = it.arguments?.getInt("type") ?: 0 val x = it.arguments?.getFloat("x") ?: 0f val y = it.arguments?.getFloat("y") ?: 0f Timber.i("Preview image: $id, $type, $x, $y") val viewModel: PreviewImageViewModel = koinViewModel { parameterSetOf(id, type) } PreviewImageScreen( viewModel = viewModel, onBack = { navController.navigateUp() } ) }
原因分析
核心差异在于代码的执行时机:
- 动画配置块(
enterTransition/exitTransition)的执行逻辑会在导航触发后立即启动,此时目标页面的initialState还未完成导航参数的绑定注入,所以arguments为空。 - 而Composable的lambda代码块是在页面初始化渲染阶段执行的,此时导航参数已经完成绑定并注入到页面的
arguments中,因此能正常获取到值。
解决方案
通过页面对应的navBackStackEntry获取参数即可解决。导航过程中,navBackStackEntry会提前持有完整的导航参数信息,不受页面参数绑定时机的影响:
修改动画配置代码如下:
enterTransition = { // 进入动画用targetState的navBackStackEntry,对应要打开的页面 val navBackStackEntry = targetState.navBackStackEntry val offsetX = navBackStackEntry.arguments?.getFloat("x") ?: 0f val offsetY = navBackStackEntry.arguments?.getFloat("y") ?: 0f scaleIn( animationSpec = tween(durationMillis = 5000), transformOrigin = TransformOrigin(offsetX, offsetY) ) }, exitTransition = { // 退出动画用initialState的navBackStackEntry,对应要关闭的页面 val navBackStackEntry = initialState.navBackStackEntry val offsetX = navBackStackEntry.arguments?.getFloat("x") ?: 0f val offsetY = navBackStackEntry.arguments?.getFloat("y") ?: 0f Timber.i("Offset: $offsetX, $offsetY") scaleOut( animationSpec = tween(durationMillis = 5000), transformOrigin = TransformOrigin(offsetX, offsetY) ) }
内容的提问来源于stack exchange,提问作者Rofie Sagara
相关产品推荐
相关产品推荐

