Jetpack Compose嵌套导航图如何传递参数供内部所有composable使用
Compose嵌套导航图全图共享参数实现方案
这个需求完全可以实现,从Navigation Compose 2.4.0版本开始,原生支持嵌套导航图层级的参数传递,不需要为每个子目的地单独声明参数。核心逻辑为:嵌套导航图本身会对应一个独立的NavBackStackEntry实例,该实例的参数会在导航到该图时赋值,整个导航图生命周期内都可以从该实例中读取参数,子页面无需单独定义参数。
具体实现步骤
1. 声明嵌套导航图参数
在定义navigation导航块时,通过arguments参数声明导航图需要接收的参数,用法和composable的参数声明完全一致:
navigation( route = "dashboard?classId={classId}", startDestination = Route.ScreenOne.route, // 给导航图声明参数,和composable的arguments用法一致 arguments = listOf( navArgument("classId") { type = NavType.StringType defaultValue = "" } ) ) { // 子页面路由不需要额外加classId参数 composable(Route.ScreenOne.route) { entry -> // 获取当前嵌套导航图对应的BackStackEntry val parentEntry = remember(entry) { navController.getBackStackEntry("dashboard?classId={classId}") } // 从父导航图的参数中读取classId val classId = parentEntry.arguments?.getString("classId") ?: "" ScreenOne(classId) } composable(Route.ScreenTwo.route) { entry -> val parentEntry = remember(entry) { navController.getBackStackEntry("dashboard?classId={classId}") } val classId = parentEntry.arguments?.getString("classId") ?: "" ScreenTwo(classId) } composable(Route.ScreenThree.route) { entry -> val parentEntry = remember(entry) { navController.getBackStackEntry("dashboard?classId={classId}") } val classId = parentEntry.arguments?.getString("classId") ?: "" ScreenThree(classId) } }
2. 导航时传参
跳转至嵌套导航图时,正常传递参数即可:
// 示例:跳转到dashboard导航图,传入classId为1001 navController.navigate("dashboard?classId=1001")
优化方案
封装参数读取逻辑
避免每个子页面重复写读取逻辑,可以将参数读取封装为可复用的Compose函数:
@Composable fun rememberDashboardClassId(navController: NavController): String { return remember { navController.getBackStackEntry("dashboard?classId={classId}") .arguments?.getString("classId") ?: "" } }
子页面调用即可直接获取参数:
composable(Route.ScreenOne.route) { val classId = rememberDashboardClassId(navController) ScreenOne(classId) }
配合导航图级ViewModel共享状态
如果需要在导航图内不仅共享参数,还要共享业务状态,可以给导航图的NavBackStackEntry创建ViewModel,整个导航图内的子页面会共享同一个ViewModel实例:
// 导航图内子页面读取ViewModel composable(Route.ScreenOne.route) { entry -> val parentEntry = remember(entry) { navController.getBackStackEntry("dashboard?classId={classId}") } // 基于父导航图的entry创建ViewModel,全图共享 val viewModel: DashboardViewModel = viewModel(parentEntry) ScreenOne(viewModel.classId, viewModel) }
注意事项
- 调用
getBackStackEntry时传入的路由字符串,必须和导航图声明的路由完全一致,包括参数占位符部分,否则会找不到对应实例 - 导航图的参数仅在该导航图的生命周期内有效,导航出该图后对应的
NavBackStackEntry会被回收,参数也会随之销毁
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

