Type Safe Nested Navigation in Jetpack Compose
In This artical we will learn about new type safe nested navigation in jetpack compose.
I hope you already know about navigation in jetpack compose.If you are new please check out this links:
Why Nested Navigation ?
In Nested Navigation we can create smaller group semilier kind of screens together rather than putting all of the screens in liner order.
Let’s Take an example:
let’s say we have a few screens SPLASH , EMAIL_LOGIN , EMAIL_SIGNUP, HOME , LIBRARY. Now if we try to navigate wihtout nested navigation the graph looks something like this:
SPLASH →EMAIL_LOGIN — EMAIL_SIGNUP → HOME — LIBRARY
Now if we devide EMAIL_LOGIN , EMAIL_SIGNUP under auth and HOME , LIBRARY under App, then it’s simpler to understant and scalable.
SPLASH
AUTH
- EMAIL_LOGIN
- EMAIL_SIGNUP
APP
- HOME
- LIBRARY
This is The Implementation:
Let’s Define the Graph:
@Serializable
sealed class Screens {
@Serializable
object Auth {
@Serializable
object EmailSignUp
@Serializable
object EmailLogIn
}
@Serializable
object App {
@Serializable
data class Home(
val name: String = "default",
)
}
}
In this code we defined the Screens and we are grouped them under some geenreal name. The Kotlin @Serializable annotation is importent for it to work.
Let’s Define The NavHost:
@Composable
fun NestedNavStartDestination() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = Screens.Auth
) {
authGraph(navController)
appGraph(navController)
}
}
startDestination = Screens.Auth
we are defining Auth group as Start Destination.
Now let’s craete 2 NavGraphBuilder extention function named:
1. authGraph
2. appGraph
private fun NavGraphBuilder.authGraph(
navController: NavHostController,
) {
// navigation extention fun
}
private fun NavGraphBuilder.appGraph(
navController: NavHostController,
) {
// navigation extention fun
}
Creating extention function increasses code readabality. and keeps it clean.Now let’s put the intented screens on this extentin functions.
private fun NavGraphBuilder.authGraph(
navController: NavHostController,
) {
navigation<Screens.Auth>(
startDestination = Screens.Auth.EmailLogIn
) {
composable<Screens.Auth.EmailLogIn> {
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Spacer(modifier = Modifier.weight(1f))
Text(
text = "Email LogIn Screen",
fontSize = MaterialTheme.typography.titleLarge.fontSize,
fontWeight = FontWeight.SemiBold
)
Spacer(modifier = Modifier.weight(3f))
Text(
text = "Email SingUp",
modifier = Modifier.clickable {
navController.popBackStack()
navController.navigate(Screens.Auth.EmailSignUp)
}
)
Spacer(modifier = Modifier.weight(1f))
Text(
text = "Auth Success",
modifier = Modifier.clickable {
navController.popBackStack()
navController.navigate(
Screens.App.Home(
name = "Old User"
)
)
}
)
Spacer(modifier = Modifier.weight(3f))
}
}
composable<Screens.Auth.EmailSignUp> {
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Spacer(modifier = Modifier.weight(1f))
Text(
text = "Email SignUp Screen",
fontSize = MaterialTheme.typography.titleLarge.fontSize,
fontWeight = FontWeight.SemiBold
)
Spacer(modifier = Modifier.weight(3f))
Text(
text = "Email LogIn",
modifier = Modifier.clickable {
navController.popBackStack()
navController.navigate(Screens.Auth.EmailLogIn)
}
)
Spacer(modifier = Modifier.weight(1f))
Text(
text = "Auth Success",
modifier = Modifier.clickable {
navController.popBackStack()
navController.navigate(
Screens.App.Home(
name = "New User"
)
)
}
)
Spacer(modifier = Modifier.weight(3f))
}
}
}
}
A lot of thing went on this section let’s break it down.
composable<Screens.Auth.EmailLogIn> {
}
composable<Screens.Auth.EmailSignUp> {
}
This are the main composable block in which we created designated composable screens.
In composable<Screen.Auth.EmailLogIn> we created a simple composable where :
Text(
text = "Email SingUp",
modifier = Modifier.clickable {
navController.popBackStack()
navController.navigate(Screens.Auth.EmailSignUp)
}
)
This block of code navigate to EmailSignUp Screen.
Text(
text = "Auth Success",
modifier = Modifier.clickable {
navController.popBackStack()
navController.navigate(
Screens.App.Home(
name = "Old User"
)
)
}
)
This block of code navigate us to Home Screen.
Now Our Home Screen takes expects a paramter to navigate and this is the beauty of type safe naviigation we can just create a object of the class that Home Scrren expects and pass it on navigation().
For composable<Screen.Auth.EmailSingup>:
Text(
text = "Email LogIn",
modifier = Modifier.clickable {
navController.popBackStack()
navController.navigate(Screens.Auth.EmailLogIn)
}
)
This block of code navigate us to EmailLogIn Screen.
Text(
text = "Auth Success",
modifier = Modifier.clickable {
navController.popBackStack()
navController.navigate(
Screens.App.Home(
name = "New User"
)
)
}
)
This will navigate us to Home Scrren with param “New User”.
This is the composable for Home Screen.
private fun NavGraphBuilder.appGraph(
navController: NavHostController,
) {
navigation<Screens.App>(
startDestination = Screens.App.Home::class
) {
composable<Screens.App.Home> {
Column(
modifier = Modifier
.fillMaxSize()
.navigationBarsPadding()
.padding(56.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
val user = it.toRoute<Screens.App.Home>().name
Spacer(modifier = Modifier.weight(2f))
Text(
text = "Home Screen",
fontSize = MaterialTheme.typography.titleLarge.fontSize,
fontWeight = FontWeight.SemiBold
)
Spacer(modifier = Modifier.weight(1f))
Text(
text = "Hello $user",
modifier = Modifier.clickable {
navController.popBackStack()
navController.navigate(Screens.Auth.EmailLogIn)
}
)
Spacer(modifier = Modifier.weight(3f))
}
}
}
}
Notice as Home Screen takes a parameter we are definig KClass on start destitaion.
startDestination = Screens.App.Home::class
And on this block of code we just navigate back to Email Login Screen
Text(
text = "Hello $user",
modifier = Modifier.clickable {
navController.popBackStack()
navController.navigate(Screens.Auth.EmailLogIn)
}
)
Please Keep in mind Only use Nested Navigation if you have a very complex project. Don’t make simple porjects un-necessarily complex. Jetpack Navigation examples are moe than enough for porject with fewer screens.
This is the github link of the above code:
Thank you :) happy Learning.