How to navigate using Jetpack Compose Navigation with examples
This tutorial will cover how to implement Navigation in your Jetpack Compose application using the AndroidX Compose Navigation library.
Required dependency
Include the required dependency in your project's build.gradle
file:
dependencies {
def nav_version = "2.5.0"
implementation "androidx.navigation:navigation-compose:$nav_version"
}
How to navigate between screens
Create a NavHost()
and pass a NavController
and the start route.
The NavController
is used to perform navigation operations (such as navigate to the next screen or go back). Within the lambda function pass the available destinations (screens) of your app.
A basic app with a home screen and an about screen would look like this:
val navController = rememberNavController()
NavHost(navController, startDestination = "home") {
composable("home") {
HomeScreen(onAboutClick = {
navController.navigate("about")
})
}
composable("about") {
AboutScreen()
}
}
How to pass data across destinations
When defining the route of your destination, pass in the argument(s) required as part of the route. The arguments need to be defined in a url like fashion:
route/{argument1}/{argument2}
named arguments are also supported:
route/argument1={argument1}/argument2={argument2}
pass the arguments
as parameters in your destination. Each navArgument()
requires a name and the expected type.
An example of a details screen requiring an id would look like this:
composable("details/{id}",
arguments = listOf(navArgument("id") {
type = NavType.LongType
})) {
val id = requireNotNull(it.arguments).getLong("id")
DetailsScreen(id)
}
navigate to the destination using the NavController
:
val id = 1000L
navController.navigate("details/id=$id")
How to pass optional data across destinations
Any optional data needs to be defined as a query parameter. Include them in your route appending your required arguments with a ?
:
route/{requiredArg1}?{optional}
additionally, mark the navArgument()
as nullable
:
composable(
"details/{id}?{name}",
arguments = listOf(
navArgument("id") {
type = NavType.LongType
},
navArgument("name") {
type = NavType.StringType
nullable = true
}
),
) { backStackEntry ->
val arguments = requireNotNull(backStackEntry.arguments)
val id = arguments.getLong("id")
val name = arguments.getString("name")
DetailsScreen(id, name)
}
navigate to the destination using the NavController
:
val id = 1000L
val name = "Alex"
navController.navigate("details/id=$id?name=$name")
How to navigate to the previous screen
Use the navController.popBackStack()
to remove the current destination from the back stack. This will cause the app to navigate to the previous destination, if there is one.
Keep in mind that the Navigation library follows the Principles of Navigation and will never terminate your application. If you wish to finish your activity if you are in the top-level destination of your app, use the return value of popBackStack()
and call finish()
if the value is true.
if(navController.popBackStack().not()) {
finish()
}
Checkout the Sample on Github
Check out the repository on Github and try it out on your machine: https://github.com/alexstyl/navigation-tutorial
Related Resources
- Principles of Navigation: The Navigation library expects you to follow the Principles of Navigation while implementing. It is worth being aware of them so that you can understand its behavior and how to structure you graphs.
- Compose Destinations: A library made by Rafael Costa that dramatically removes the boilerplate required for navigation.