准确的说是一个stack导航里嵌套了一个tab导航。这个时候按照文档的方法会报错。所以需要用到两个NavHost
来处理。代码在这里。APP的导航是这样的:
点了首页的todo item后跳转到todo的详情页,这个时候整个的tab都不可见。
先看tab navigator。这是是一个底部的tab。代码如下:
kotlin
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TabScreen(outerNav: NavHostController) {
val navController = rememberNavController()
val tabBarItems = listOf(
Screens.Home,
Screens.Settings,
)
val navBackStackEntry by navController.currentBackStackEntryAsState()
Scaffold(topBar = {
TopAppBar(
// removed
)
}, bottomBar = {
BottomTabBar(navController = navController, items = tabBarItems)
}) { innerPadding ->
NavHost(
navController = navController,
startDestination = Screens.Home.route,
Modifier.padding(innerPadding)
) {
composable(Screens.Home.route) {
HomeScreen(
outerNav = outerNav,
navController = navController
)
}
composable(Screens.Settings.route) {
SettingsScreen(
navController = navController,
)
}
composable(
route = Screens.AddTodo.route, // TODO: enter & exit transition?
) { AddTodoScreen(navController = navController) }
}
}
}
删掉了一些不必要的代码,但是不影响阅读。
TabScreen
接收一个参数outerNav
,这个参数随后会传入Tab导航的第一个screen也就是HomeScreen
。这样在首页点击一个todo条目的时候就可以使用外部的导航来跳转页面。
现在看看外面的导航,其实很简单:
kotlin
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MainScreen(settingsViewModel: SettingsViewModel = hiltViewModel()) {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "main") {
composable(route = "main") {
TabScreen(outerNav = navController)
}
composable(route = "${Screens.Detail.route}/{todoId}") { backStackEntry ->
DetailScreen(
navController = navController,
backStackEntry.arguments?.getString("todoId")?.toIntOrNull()
)
}
}
}
在tab导航使用的外部导航outerNav
就是在这里创建的,然后传给了TabScreen
。
总结一下,外部的stack导航的navigator传给嵌套的tab导航,然后再传递给tab导航的首页。并在首页里使用外部的导航跳转stack导航的页面。