Jetpack Compose: Navigation arguments data type

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.


MainActivity.kt

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
            )
        }
    }
}
More android jetpack compose tutorials