Reputation: 3015
I'll try to do some ASCII art to describe the problem:
<--------------------------------------\
DestinationA --> DestinationC ---------> DestinationE
DestinationB ------/ \-----> DestinationD --/
I hope that's decipherable. C can be reached from destinations A and B. E can be reached from C and D. E returns to either A or B (whichever is in the back stack). Destinations C, D, and E take an argument (id).
What is the best way to implement this? Using nested navigation graphs looks like it might be possible.
The following works, but it feels more like a work-around than how the navigation component is intended to work.
val destination = navController.getBackStackEntry("DestinationC/{id}").destination
navController.popBackStack(destination.id, true)
The usage NavHost is currently:
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "DestinationA") {
compose("DestinationA") {
ScreenA(hiltNavGraphViewModel(it))
}
compose("DestinationB") {
ScreenB(hiltNavGraphViewModel(it))
}
compose("DestinationC/{id}", arguments = listOf(navArgument("id") { type = NavType.StringType })) {
val viewModel = hiltNavGraphViewModel(it)
val id = it.arguments?.getString("id")
viewModel.setId(id)
ScreenC(viewModel)
}
compose("DestinationD/{id}", arguments = listOf(navArgument("id") { type = NavType.StringType })) {
val viewModel = hiltNavGraphViewModel(it)
val id = it.arguments?.getString("id")
viewModel.setId(id)
ScreenD(viewModel)
}
compose("DestinationE/{id}", arguments = listOf(navArgument("id") { type = NavType.StringType })) {
val viewModel = hiltNavGraphViewModel(it)
val id = it.arguments?.getString("id")
viewModel.setId(id)
ScreenE(viewModel)
}
}
Upvotes: 5
Views: 7351
Reputation: 11
Use popUpTo with the desired destination, not with the current nested nav graph, this will remove all the destinations until the destination with a matching route is found
In the below example all the routes from the nested graph up to the NavigationGraph.Welcome.route
inluded are removed
NavHost(
navController = navController,
startDestination = NavigationGraph.Welcome.route
) {
composable(
route = NavigationGraph.Welcome.route
) {
WelcomeScreen { destination ->
navController.navigate(destination)
}
}
navigation(
startDestination = LoginNavigationRoute.RefCode.route,
route = NavigationGraph.Login.route
) {
...
composable(
route = LoginNavigationRoute.SignIn.route
) {
SignInScreen(
onSuccessfulLogin = {
navController.navigate(NavigationGraph.Main.route) {
popUpTo(NavigationGraph.Welcome.route) {
inclusive = true
}
}
}
)
}
...
Upvotes: 1
Reputation: 3015
The answer from @rofie-sagara did not work for me. There is a navigation extension that supports routes. I think nested navigation is an unrelated topic. The docs don't really explain why nested navigation is actually useful. My final solutions to move from E back to A or B is:
navigation.popBackStack(route = "DestinationC/{id}", inclusive = true)
Upvotes: 7
Reputation: 323
Using nested navigation graphs Make DestinationC
and DestinationE
on diff navigations.
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "DestinationA") {
compose("DestinationA") {
ScreenA(hiltNavGraphViewModel(it))
}
compose("DestinationB") {
ScreenB(hiltNavGraphViewModel(it))
}
navigation("DestinationC".plus("/{id}"), "DestinationC".plus("_Route")) {
compose("DestinationC/{id}", arguments = listOf(navArgument("id") { type = NavType.StringType })) {
val viewModel = hiltNavGraphViewModel(it)
val id = it.arguments?.getString("id")
viewModel.setId(id)
ScreenC(ViewModel)
}
}
compose("DestinationD/{id}", arguments = listOf(navArgument("id") { type = NavType.StringType })) {
val viewModel = hiltNavGraphViewModel(it)
val id = it.arguments?.getString("id")
viewModel.setId(id)
ScreenD(viewModel)
}
navigation("DestinationE".plus("/{id}"), "DestinationE".plus("_Route")) {
compose("DestinationE/{id}", arguments = listOf(navArgument("id") { type = NavType.StringType })) {
val viewModel = hiltNavGraphViewModel(it)
val id = it.arguments?.getString("id")
viewModel.setId(id)
ScreenE(ViewModel)
}
}
}
example you want to move from C to E and popUpTo A.
navController.navigate("DestinationE".plus("/${data.id}")) {
popUpTo("DestinationA") {
inclusive = false
}
}
Upvotes: -1