Jetpack Compose: Navigation
I consider Jetpack Navigation to be one of the most useful components of the Jetpack project. Sure, it's not perfect and some cases falls short, but in general it has solved a big hustle in the Android development world. For most apps, it's more than enough.
Naturally, I was quite curious on how navigation works in this new Compose world (in which we will live soon). It turns out, it's quite different but it makes sense since there is no XML in the new world (you used to define the navigation destinations and graph using XML). But still, gets the job done efficiently and quickly, more than enough for most apps.
Navigation in the Compose world still uses Jetpack Navigations classes but is extended to support @Composable
functions. It works by swapping Composable views and keeping track of the stack.
Set up
Add these to your build.gradle
. Check for the latest version first.
dependencies {
[...]
def nav_compose_version = "1.0.0-alpha02"
implementation "androidx.navigation:navigation-compose:$nav_compose_version"
}
NavHost
NavHost is the "drawing" area that screens/destinations will be drawn in. If you navigate to a new screen, the old one will be hidden and the new one will be shown.
Each screen/destination have a route. This concept is similar to some web frameworks. A route is a string that acts as a unique path to a screen (in this case a screen is a @Composable
).
val navController = rememberNavController() // 1.
NavHost(navController, startDestination = "demo") { // 2.
composable("demo") { ScreenDemo(navController) }
composable("details") { ScreenDetails() }
}
- Use
rememberNavController()
to create a navigation controller that will be linked to yourNavHost
. Create this somewhere where you can pass it down to any screen that might need to do some navigation action. - Create the
NavHost
and declare multiple destinations using thecomposable()
method. This takes the path and the actual@Composable
that will be called when navigating to this destination.
Navigat
To navigate to a destination, use the NavHostController
and the route path you declared in NavHost
previously.
@Composable
fun ScreenDemo(navController: NavHostController) {
Demo() { navController.navigate("details") }
}
@Composable
fun Demo(onClick: () -> Unit = {}) {
Column {
BasicText("Demo")
Button(
onClick = onClick,
) {
BasicText(text = "Go to Details")
}
}
}
Note that navigate("string")
is not a NavHostController
method, but an extension method. You would need to import androidx.navigation.compose.navigate
if the IDE fails to find the method.
Arguments
But what about arguments you might say? It's quite common for additional arguments to be passed around while navigating. Don't be intimidate by the example, bear with me.
NavHost(navController, startDestination = "demo") {
composable("demo") { ScreenDemo(navController) }
composable("details/{id}", // 1.
arguments =
listOf(navArgument("id") { type = NavType.IntType } // 2.
{ backStackEntry ->
ScreenDetails(
navController,
backStackEntry.arguments?.getInt("id")!! // 3.
)
}
}
- We added an argument to this path similarly to how you would do it in a web app. You can think of the route path as URL.
- Optionally, the type of this argument can be defined. This is almost always a good idea. By default, all arguments are parsed as Strings.
- We need to extract that argument value and pass it to your
@Composable
.
Optional arguments
Use the URL query parameters syntax to declare that an argument is optional. You must provide a defaultValue
(or that is nullable
).
NavHost(navController, startDestination = "demo") {
composable("demo") { ScreenDemo(navController) }
composable("details/{id}",
arguments =
listOf(navArgument("id") {
nullable = true
type = NavType.IntType
}
{ backStackEntry ->
ScreenDetails(
navController,
backStackEntry.arguments?.getInt("id")
)
}
}
Back
Navigate back by "popping" the current screen and going back to the previous one. This is the same method you would use in the View-based Jetpack Navigation.
@Composable
fun ScreenDetails(id: Int, navController: NavHostController) {
Details(onClick = { navController.popBackStack() }, id = id)
}
@Composable
fun Details(onClick: () -> Unit = {}, id: Int) {
Column {
BasicText("Details $id")
Button(
onClick = onClick,
) {
BasicText(text = "Back")
}
}
}
This was a super quick ramp up to how navigation is done in a Jetpack Compose app. Check out the documentation for further reading. And happy navigating around!
Check out more in this Jetpack Compose exploratory series: