Type-safe navigation in Jetpack Compose allows for strong typing and safety when passing arguments between composable screens. Here's a detailed explanation of how it works, along with the provided code and comments:
Dependencies
First, you need to add the necessary dependencies for Kotlin serialization and Jetpack Navigation in Libs.toml
and build.gradle
files.
libs.version.toml
[versions]
kotlinxSerializationJson = "1.7.1"
kotlinxSerialization = "2.0.20"
navigationCompose = "2.8.0"
[libraries]
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
[plugins]
jetbrains-kotlin-serialization = { id ="org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlinxSerialization"}
build.gradle.kts
plugins {
alias(libs.plugins.jetbrains.kotlin.serialization) apply false
}
Another build.gradle.kts
file:
plugins {
alias(libs.plugins.jetbrains.kotlin.serialization)
id("kotlin-parcelize") // needed for non-primitive classes
}
dependencies {
implementation(libs.androidx.navigation.compose)
implementation(libs.kotlinx.serialization.json)
}
Data Class Definition
We create a simple data class User
to hold user-related data like ID, name, age, and gender.
data class User(
val id: Int,
val name: String,
val age: Int,
val gender: String
)
Defining Navigation Routes with Serialization
The NavRoutes
sealed class defines the possible screens in the app. Each screen can have parameters passed, making navigation type-safe.
@Serializable
sealed class NavRoutes {
// ListScreen with no arguments
@Serializable
data object ListScreen: NavRoutes()
// UserDetailScreen that accepts parameters for user details
@Serializable
data class UserDetailScreen(
val id: Int,
val name: String,
val age: Int,
val gender: String
): NavRoutes()
}
ListScreen (First Screen)
In this screen, we display a list of users from popular anime characters. The items are arranged in a LazyColumn, and each user is clickable, navigating to a detailed screen.
@Composable
fun ListScreen(navController: NavController) {
// Sample user data (anime characters)
val myUser = listOf(
User(1, "Naruto", 14, "Male"),
User(2, "TenTen", 15, "Female"),
User(3, "Hinata", 14, "Female"),
User(4, "Shikamaru", 15, "Male"),
User(5, "Sakura", 15, "Female"),
User(6, "Kakashi", 23, "Male")
)
// Display the user list in a LazyColumn
LazyColumn(
modifier = Modifier.padding(15.dp) // Add padding to the list
) {
// Iterate over the list of users and display each as a SingleUser composable
items(myUser) {
SingleUser(navController, name = it.name, id = it.id, age = it.age, gender = it.gender)
}
}
}
SingleUser
This composable represents an individual user in the list. Itβs clickable and navigates to the UserDetailScreen when selected.
@Composable
fun SingleUser(navController: NavController, id: Int, name: String, age: Int, gender: String) {
Row(
modifier = Modifier
.fillMaxSize()
.padding(5.dp) // Add padding around each user entry
.clip(RoundedCornerShape(30.dp)) // Rounded corners for a polished look
.background(Color.LightGray) // Light gray background color
.clickable {
// Navigate to UserDetailScreen with the user's details
navController.navigate(
NavRoutes.UserDetailScreen(
id = id,
age = age,
name = name,
gender = gender
)
)
},
horizontalArrangement = Arrangement.SpaceEvenly, // Space out elements evenly
verticalAlignment = Alignment.CenterVertically // Align items vertically in the center
) {
// Display user's name, age, and gender with a font size of 15sp
Text(text = name, fontSize = 15.sp)
Text(text = age.toString(), fontSize = 15.sp)
Text(text = gender, fontSize = 15.sp)
}
}
UserDetailScreen (Second Screen)
This screen displays detailed information about a selected user. The user can also navigate back to the list.
@Composable
fun UserDetailScreen(navController: NavController, name: String, age: Int, gender: String) {
Column(
modifier = Modifier.fillMaxSize(), // Take full available space
horizontalAlignment = Alignment.CenterHorizontally, // Align content horizontally in the center
verticalArrangement = Arrangement.Center // Align content vertically in the center
) {
// Display user name, age, and gender with some spacing in between
Text(text = name, fontSize = 20.sp) // Name with larger font size
Spacer(modifier = Modifier.height(5.dp)) // Spacer between text elements
Text(text = age.toString(), fontSize = 20.sp)
Spacer(modifier = Modifier.height(5.dp))
Text(text = gender, fontSize = 20.sp)
Spacer(modifier = Modifier.height(5.dp))
// Back button to return to the previous screen
Button(onClick = { navController.popBackStack() }) {
Text(text = "Back")
}
}
}
MainActivity Setup
In the NavigationExample
activity, we set up navigation using NavHost
. It maps the NavRoutes
to corresponding composables.
class NavigationExample: ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
// Create a NavController to handle navigation
val navController = rememberNavController()
// Define the NavHost which manages the navigation graph
NavHost(navController = navController, startDestination = NavRoutes.ListScreen) {
// Composable for ListScreen
composable<NavRoutes.ListScreen> {
ListScreen(navController)
}
// Composable for UserDetailScreen with safely passed arguments
composable<NavRoutes.UserDetailScreen> { navBackStackEntry ->
val args = navBackStackEntry.toRoute<NavRoutes.UserDetailScreen>()
UserDetailScreen(navController, args.name, args.age, args.gender)
}
}
}
}
}
Explanation
-
Type Safety:
NavRoutes
uses Kotlin's sealed classes and serialization to safely pass arguments between screens, ensuring type safety. When navigating, you can only pass the expected arguments. -
Serialization: The
@Serializable
annotation allows passing complex data types (like objects) through the navigation system in a type-safe way. -
Back Navigation: On the
UserDetailScreen
, you can navigate back usingnavController.popBackStack()
.
Output
This setup allows for safe and robust navigation between screens with parameterized data in Jetpack Compose.
Now, itβs time to unleash your new superpowers on the coding world!
<aside>
<p>
Thanks for taking the time to read!<br>
If you found this post helpful,<br>
I'd appreciate a clap. π
</p>
</aside>
Top comments (0)