Jetpack Compose: Navigation
A Practical Introduction #
In this tutorial, you’ll learn the basics of Jetpack Compose Navigation, which is a set of related classes that help you create clearly structured and easy-to-understand code for navigation in your Android app. By using these classes, you’ll be able to simplify the navigation code and make it more organized, which will make it easier to maintain and update. Let’s get started!
This is what we will build:
The animation below shows a finished example application where the user can navigate between several different views. To achieve this, the tutorial will guide you through the use of the NavHost
, NavController
, and Navigation
composable functions.
Dependencies #
To use Jetpack Compose Navigation, you need to add the following dependency to your build.gradle
:
dependencies {
...
implementation 'androidx.navigation:navigation-compose:2.5.3'
}
The Code #
The code below shows the full example of the Jetpack Compose Navigation animation above. We’ll go through it step-by-step in the following paragraphs.
@Composable
fun NavigationView() {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
composable("home") {
HomeScreen(navController)
}
composable("settings") {
SettingsScreen(
onHome = { navController.popBackStack() },
onProfile = { navController.navigate("profile") }
)
}
composable("profile") {
ProfileScreen { navController.popBackStack("home", false) }
}
}
}
@Composable
fun HomeScreen(navController: NavHostController) {
Column(
Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text("Home Screen")
Button(onClick = { navController.navigate("settings") }) {
Text("Go to Settings")
}
Button(onClick = { navController.navigate("about") }) {
Text("Go to About")
}
}
}
@Composable
fun SettingsScreen(onHome: () -> Unit, onProfile: () -> Unit) {
Column(
Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text("Settings Screen")
Button(onClick = onHome) { Text("Go back to Home") }
Button(onClick = onProfile) { Text("Go to Profile") }
}
}
@Composable
fun ProfileScreen(onHome: () -> Unit) {
Column(
Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Button(onClick = onHome) {
Text("Go back to Home")
}
}
}
The full Android Studio project can be found in my Github-repository of Android and iOS code examples.
A basic example of Jetpack Compose Navigation includes the following components: NavHost
, **NavController,
**and Navigation
composable. The NavHost
is the container that holds all of the navigation destinations within the app. The NavController
is responsible for managing the navigation between different destinations and the Navigation
composable is used to declare a specific destination within the NavHost
.
The navigation stack refers to the order of composables that the user has navigated through, with the current composable being the top of the stack. navigate
, popUpTo
, and popBack
are all functions used to manage the navigation stack. The class responsible for the navigation stack is the NavHost
composable.
navigate
is used to navigate from one composable to another composable, such as from HomeScreen
to SettingsScreen
in this example. The navigate
function takes two arguments, the first being the destination
composable name as a string, and the second being an optional argument for passing data to the destination composable.
popUpTo
is used to navigate back to a specific composable in the navigation stack. It takes the destination
composable name as an argument and discards all composables that were added after it. In this example, popUpTo("home")
navigates back to the HomeScreen
composable while discarding the SettingsScreen
and ProfileScreen
composables.
popBack
is used to navigate back one step in the navigation stack. It discards the current composable and takes the user back to the previous composable in the stack. In this example, popBack()
takes the user back to the SettingsScreen
composable from the AboutScreen
composable.
In the provided code, there are two areas that could be improved.
Firstly, passing the navController into a view is considered an anti-pattern and should be avoided. Views should not be aware of any navigation aspects, but should only inform the parent about a certain event that might require navigation. This way, the parent can handle the navigation logic without involving the view.
Secondly, using Strings directly for the navigation routes presents a potential problem. A simple typo can cause your code to crash, making debugging difficult. Instead, it is recommended to use enums or sealed classes to represent navigation routes. This approach provides compile-time safety, ensuring that typos and incorrect navigation routes are caught before runtime.
By implementing these best practices, your code will be easier to maintain, more organized, and less prone to errors.
That wraps up this brief introduction to the topic. I trust you found it both helpful and informative. Please don’t hesitate to leave a comment if you have any questions or suggestions.
Thank you for reading!
- If you enjoyed this, please follow me on Medium
- Buy me a coffee or send me a tip
- Support me and other Medium writers by signing up here
https://twissmueller.medium.com/membership