Introduction
Jetpack Compose, Android's modern toolkit for building native UI, simplifies UI development by allowing declarative programming and removing the need for XML layouts. One key feature is the ability to implement navigation using the NavHost
and NavController
classes. This tutorial breaks down a Kotlin example demonstrating how to navigate between screens and pass arguments of different data types using Jetpack Compose.
In this example, we will explore how to pass a string and a long data type as arguments during navigation between two composable screens. The first screen displays a list of color names, while the second screen, accessed by clicking on a color, shows the selected color with its hexadecimal value applied to the background.
Main Structure
The application begins in MainActivity
, which hosts the app's composable functions using setContent
. Instead of traditional XML layouts, we define the UI inside composable functions. The GetScaffold()
function sets up a Scaffold
, a basic layout structure that provides a top app bar and space for content. This is where our screens will be placed.
Within MainContent()
, we use a NavHostController
for navigation. The NavHost
component defines navigation routes and composable screens. The startDestination
parameter specifies that the app will first load the ListScreen
, where we will present a list of clickable color options. Clicking an option navigates to DetailsScreen
, passing both the color name and its hexadecimal value as arguments.
Navigating with Arguments
Jetpack Compose's navigation supports passing arguments of various types, including primitive types like strings and integers. In the MainNavigation()
function, we define two composable routes: listScreen
and detailsScreen/{colorName}/{hexValue}
. The detailsScreen
route expects two arguments: a string (colorName
) and a long (hexValue
). These arguments are declared using navArgument
, which ensures type safety by defining the expected data type (NavType.StringType
and NavType.LongType
).
When the user clicks a color option in the ListScreen
, the NavController
triggers navigation using the navigate()
method, passing the color name and hexadecimal value dynamically in the URL-like route string.
Displaying a List of Colors
The ListScreen
function contains a map of colors with their respective hexadecimal values. This data structure is iterated over to generate a list of clickable cards, where each card represents a color. The clickable
modifier is attached to each card, and upon clicking, the NavController
is used to navigate to the DetailsScreen
. The selected color's name and hex value are appended to the navigation route.
Displaying the Selected Color
The DetailsScreen
function retrieves the passed arguments using backStackEntry
. These values—colorName
(a string) and hexValue
(a long)—are then used to configure the UI. Specifically, the screen’s background color is set using the hexadecimal value passed from ListScreen
. Additionally, the color’s name is displayed in the center of the screen.
Summary
This example demonstrates how to use Jetpack Compose’s navigation component to pass arguments between screens in an Android application. By leveraging Jetpack Compose's type-safe navigation, developers can easily pass data like strings and numbers between composable functions. This approach streamlines UI management while ensuring a clean, reactive design pattern that eliminates the need for XML layouts.
Jetpack Compose makes Android development faster and more intuitive, and integrating navigation with argument passing ensures robust, dynamic user experiences. This example serves as a foundation for more complex applications that require interaction between multiple screens and data types.
package com.cfsuman.jetpackcompose
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import androidx.navigation.NavHostController
import androidx.navigation.NavType
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
GetScaffold()
}
}
@Composable
fun GetScaffold(){
val navController:NavHostController = rememberNavController()
Scaffold(
topBar = {
TopAppBar(
title = { Text(
text = "Compose - Nav Arguments Data Type"
)},
backgroundColor = Color(0xFFC0E8D5),
)
},
content = {MainContent(navController)},
backgroundColor = Color(0xFFEDEAE0),
)
}
@Composable
fun MainContent(navController: NavHostController){
Box(
modifier = Modifier.fillMaxSize(),
){
MainNavigation(navController)
}
}
@Composable
fun MainNavigation(navController: NavHostController){
NavHost(
navController = navController,
startDestination = "listScreen"
){
composable("listScreen"){ListScreen(navController)}
composable(
route = "detailsScreen/{colorName}/{hexValue}",
arguments = listOf(
navArgument("colorName") { type = NavType.StringType },
navArgument("hexValue") { type = NavType.LongType }
)
){ backStackEntry ->
DetailsScreen(
backStackEntry.arguments?.getString("colorName"),
backStackEntry.arguments?.getLong("hexValue")
)
}
}
}
@Composable
fun ListScreen(navController: NavController){
val maps = mapOf<String,Long>(
Pair("Brick red",0xFFCB4154),
Pair("Baby blue",0xFF89CFF0),
Pair("Apple green",0xFF8DB600),
Pair("Burnt sienna",0xFFE97451),
Pair("Cameo pink",0xFFEFBBCC)
)
Column(
modifier = Modifier
.fillMaxWidth()
.padding(4.dp),
verticalArrangement = Arrangement.spacedBy(4.dp),
horizontalAlignment = Alignment.Start
) {
Text(
text = "List Screen",
style = MaterialTheme.typography.h4,
modifier = Modifier.padding(bottom = 24.dp)
)
maps.forEach {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(1.dp)
.height(50.dp)
.clickable {
navController
.navigate(
"detailsScreen/${it.key}/${it.value}"
)
}
) {
Box(modifier = Modifier
.fillMaxSize()
.wrapContentSize(Alignment.Center)) {
Text(text = it.key)
}
}
}
}
}
@Composable
fun DetailsScreen(colorName:String?, hexValue:Long?){
Box(
modifier = Modifier
.fillMaxSize()
.background(Color(hexValue?: 0xFFFFFF)),
contentAlignment = Alignment.Center
) {
Text(
text = "${colorName?.apply {}}",
style = MaterialTheme.typography.h4,
modifier = Modifier.padding(bottom = 24.dp),
textAlign = TextAlign.Center
)
}
}
}
- jetpack compose - How to use navigation controller
- jetpack compose - Navigate with argument
- jetpack compose - Navigation multiple arguments
- jetpack compose - Navigation object argument
- jetpack compose - WebView ProgressIndicator
- jetpack compose - WebView progress percentage
- jetpack compose - Backdrop scaffold
- jetpack compose - Double click listener
- jetpack compose - Long click listener
- jetpack compose - Pass onClick event to function
- jetpack compose - TabRow custon indicator
- jetpack compose - Get primary language
- jetpack compose - Get screen orientation
- jetpack compose - How to change NavigationBar color
- jetpack compose - How to change SystemBars color