Jetpack Compose导航至子页面时BottomNavigation项保持选中方案
问题根源
你对NavDestination.hierarchy的理解存在偏差:该属性遍历的是 当前目的地到所属各级导航图的层级链,而非返回栈中的历史目的地列表。
你目前将GameDetailScreen作为根NavHost下的平级路由声明,它的层级链仅包含自身、根NavGraph节点,完全不包含GameListScreen节点,自然无法匹配到Search Tab对应的路由,导致选中状态丢失。
实现方案
方案1:嵌套导航图(官方推荐写法)
将同属一个底部Tab的所有页面归到同一个嵌套导航图下,给嵌套图设置和对应Tab项完全一致的路由,此时子页面的层级链会自动包含嵌套图的路由,无需修改选中判断逻辑:
修改NavHost的路由声明:
@Composable fun Navigation(navController: NavHostController) { NavHost( navController = navController, startDestination = Screen.Home.route ) { composable(Screen.Home.route) { HomeScreen() } // 搜索Tab对应的嵌套导航图,根路由和Tab绑定路由一致 navigation( startDestination = Screen.GameListScreen.route, route = Screen.GameListScreen.route ) { composable(Screen.GameListScreen.route) { GameListScreen(navController) } composable( route = "${Screen.GameDetailScreen.route}/{gameId}", arguments = listOf(navArgument("gameId") { type = NavType.IntType }) ) { GameDetailScreen() } } composable(Screen.Profile.route) { ProfileScreen() } } }
修改完成后,进入游戏详情页时,currentDestination.hierarchy会包含上层嵌套图的路由(即Search Tab绑定的Screen.GameListScreen.route),原有选中判断逻辑会自动生效,对应Tab保持选中。
方案2:路由映射匹配
如果不想调整现有导航结构,可以手动维护每个Tab对应的子路由集合,匹配时判断当前页面是否属于对应Tab的路由范围:
- 扩展BottomNavItem数据结构,增加子路由字段
data class BottomNavItem( val name: String, val route: String, val icon: ImageVector, val badgeCount: Int = 0, val childRoutes: List<String> = emptyList() // 该Tab下所有子页面路由 )
- 初始化导航项时,给Search Tab配置子路由
BottomNavItem( name = "Search", route = Screen.GameListScreen.route, icon = Icons.Default.Search, childRoutes = listOf("${Screen.GameDetailScreen.route}/{gameId}") )
- 修改BottomNavigationItem的选中逻辑
val currentRoute = navBackStackEntry?.destination?.route BottomNavigationItem( selected = currentRoute == item.route || item.childRoutes.any { routePattern -> currentRoute?.matches(Regex(routePattern)) == true }, // 其余参数保持原有逻辑即可 onClick = { onItemClick(item) }, // ... )
额外注意
从列表页跳详情页时,不要复用底部Tab的跳转配置(即不要加popUpTo到起始目的地、restoreState那套逻辑),直接调用navController.navigate("${Screen.GameDetailScreen.route}/$gameId")即可,否则会将列表页弹出返回栈,按返回键时直接回到首页,不符合交互预期。
内容的提问来源于stack exchange,提问作者Thomas Göhringer
相关产品推荐
相关产品推荐

