NavController
The central component for navigation in Compose: - tracks back stack composable entries - moves the stack forward - enables back stack manipulation - navigates between destination states
Because of how central it is, it is the first step for setting up navigation.
The NavController is obtained by calling rememberNavController(). This should always be done in the top level of your composable hierarchy.
@Composable
fun MyApp() {
MyAppTheme {
val navController = rememberNavController()
// ...
Scaffold(
// ...
) {
// ...
}
}
}
NavHost
Part 2 of the 3 components required for navigation. The NavHost acts as a container and is responsible for displaying the current destination of the graph. Every NavController should always be associated with exactly one NavHost. It also serves to link the NavController to the third component, the NavGraph, which maps out the composable destinations to navigate between.
When creating the NavHost, you also must specify the startDestination route of which screen to display when the app is opened.
Scaffold(...) {
NavHost(
navController = navController,
startDestination = HomeScreen.route /*a string*/,
) {
//...
}
}
NavGraph
Part 3 of 3. Acts as the destination/route handler, and is defined using the NavGraphBuilder.composable extension function. Each screen needs to individually have it's route and matching screen added.
NavHost(...){
composable(route = HomeScreen.route){
HomeScreen()
}
composable(route = SettingsScreen.route){
SettingsScreen()
}
}
From here, you can react to an appropriate button press within your app by calling
navController.navigate(newRoute)
Navigation Options
These come from the NavOptionsBuilder class, and are for use with calls to navController.navigate()
- launchSingleTop : ensures that only one instance of each screen exists. If false, each call to navigate() will launch a new instance
- popUpTo(route) {saveState = true} : pops up to the beginning of the back stack, removing long chains of screens.
- restoreState : should state (such as scroll position) be saved and restored when navigating between screens?
Passing Screen Changes
In the cases where you need to know the current screen (like a custom tab row that shows the selected tab a different color), we can get the top of the backstack from the NavController. Because this is returned as a NavDestination, you'll also need a way to connect it to one of your screens (i.e. using the route String as a psuedo id).
val navController = rememberNavController()
val currentBackStack by navController.currentBackStackEntryAsState()
val currentDestination = currentBackStack?.destination
Aside:
list.findA handy shortcut Kotlin method
kotlin val currentScreen = TabRowScreens.find {it.route == currentDestination.route} ?: Overviewis equivalent tokotlin var currentScreen = Overview for (screen in TabRowScreens) { if (screen.route == currentDestination.route) currentScreen = screen }