Navigation 3中如何从单一位置跨Graph导航至Route?
问题描述
迁移至Navigation 3前,我通过单一Route类型实现了如下深度链接重定向逻辑:
Navigation 2 - Route.ValidatePin:
PinScreen( onNext = { val destination = deeplinkViewModel.getAndConsumeDestination() if (destination != null) { // 从深度链接跳转时,将Home图作为起始目标 navController.migrateAuthGraphTo(graph = Graph.Home) navController.navigate(route = destination) { launchSingleTop = true } } else { navController.migrateAuthGraphTo(graph = Graph.Home) } })
我正尝试在Navigation 3中复刻该重定向逻辑,核心是找到navController.navigate(route = destination)的等效实现。
destination是视图模型返回的深度链接目标Route,如果有助于Navigation 3的配置,我可以修改ViewModel,让它同时返回该Route所属的Graph。
当前的问题是:重定向目标可能属于不同的Graph,而每个Graph都有独立的rememberNavBackStack()实例,我想知道有没有简便的方法能从单一位置实现跨Graph的Route导航。
项目架构
我的项目导航架构如下:
- 每个导航条目对应一个
@Serializable数据类/对象 - 为
Route和Graph分别定义了密封接口
AuthGraph实现:
@Composable fun AuthNavigation( modifier: Modifier = Modifier, deeplinkViewModel: DeeplinkViewModel, goToHome: () -> Unit, ) { val authBackStack = rememberNavBackStack(Route.ScreensSetup) NavDisplay( backStack = authBackStack, entryProvider = entryProvider { entry<Route.ValidatePin> { PinScreen( onNext = { // 逻辑同上述代码示例 }, ) } }, ) }
NavHost实现:
@Composable fun MKsiadzNavHost(){ val rootBackStack = rememberNavBackStack() NavDisplay( backStack = rootBackStack, onBack = { rootBackStack.removeLastOrNull() }, entryDecorators = listOf( rememberSaveableStateHolderNavEntryDecorator(), rememberViewModelStoreNavEntryDecorator() ), entryProvider = entryProvider { entry<Graph.Auth> { AuthNavigation(deeplinkViewModel =... , goToHome =...) { } } entry<Graph.Home> { HomeNavigation(goToForms = {}, goToAnnouncement = {}) })}
解决方案
针对Navigation 3的模块化导航特性,可以通过全局导航函数+明确Graph归属的方式实现跨Graph重定向,步骤如下:
1. 封装深度链接目标信息
修改ViewModel,让它返回包含目标Graph和对应Route的封装数据,确保能明确导航目标所属的Graph:
// 定义数据类,封装Graph和Route配对信息 data class DeeplinkDestination(val graph: Graph, val route: Route) // 在DeeplinkViewModel中更新返回类型 fun getAndConsumeDestination(): DeeplinkDestination? { // 原有逻辑,返回封装后的目标数据 }
2. 在根导航层定义全局导航函数
在MKsiadzNavHost中统一管理所有子Graph的back stack,并提供全局导航函数,处理跨Graph的跳转逻辑:
@Composable fun MKsiadzNavHost(){ val rootBackStack = rememberNavBackStack() // 初始化各子Graph的back stack val authBackStack = rememberNavBackStack(Route.ScreensSetup) val homeBackStack = rememberNavBackStack(HomeRoute.HomeScreen) // 替换为Home的初始Route // 全局导航函数:处理跨Graph的深度链接跳转 val navigateToDeeplink: (DeeplinkDestination) -> Unit = { dest -> // 切换到目标Graph(替换根back stack) rootBackStack.setNewRoot(dest.graph) // 根据目标Graph,将Route推入对应子back stack when(dest.graph) { is Graph.Auth -> authBackStack.push(dest.route) is Graph.Home -> homeBackStack.push(dest.route) // 其他Graph同理扩展 } } NavDisplay( backStack = rootBackStack, onBack = { rootBackStack.removeLastOrNull() }, entryDecorators = listOf( rememberSaveableStateHolderNavEntryDecorator(), rememberViewModelStoreNavEntryDecorator() ), entryProvider = entryProvider { entry<Graph.Auth> { AuthNavigation( deeplinkViewModel = ..., navigateToDeeplink = navigateToDeeplink, goToHome = { rootBackStack.setNewRoot(Graph.Home) } ) } entry<Graph.Home> { HomeNavigation( goToForms = {}, goToAnnouncement = {}, navigateToDeeplink = navigateToDeeplink // 若Home也需处理深度链接,传递该函数 ) } } ) }
3. 在AuthGraph中调用全局导航函数
修改AuthNavigation,接收全局导航函数,替换原有跳转逻辑:
@Composable fun AuthNavigation( modifier: Modifier = Modifier, deeplinkViewModel: DeeplinkViewModel, navigateToDeeplink: (DeeplinkDestination) -> Unit, goToHome: () -> Unit, ) { val authBackStack = rememberNavBackStack(Route.ScreensSetup) NavDisplay( backStack = authBackStack, entryProvider = entryProvider { entry<Route.ValidatePin> { PinScreen( onNext = { val destination = deeplinkViewModel.getAndConsumeDestination() if (destination != null) { // 调用全局导航函数处理跨Graph跳转 navigateToDeeplink(destination) } else { // 正常跳转到Home Graph goToHome() } }, ) } }, ) }
关键说明
rootBackStack.setNewRoot(dest.graph):对应Navigation 2中的migrateAuthGraphTo,用于切换根导航GraphxxxBackStack.push(dest.route):对应Navigation 2中的navigate(route),将目标Route推入对应Graph的back stack- 全局导航函数统一处理跨Graph逻辑,避免在子Graph中分散处理,符合Navigation 3的模块化设计理念
内容的提问来源于stack exchange,提问作者Stanisław Olszak
相关产品推荐
相关产品推荐

