KMPizza
Kotlin Multiplatform + Pizza = ❤️

Step 17: Add Navigation to Jetpack Compose UI

Now that we have both RecipesScreen and RecipeDetailScreen, we can set up navigation.

Clicking on one of the list items, the user will navigate from main screen to the details screen of the recipe with the chosen id.

First, we need a couple of routes that we’ve already discussed when designing our app.

Add utils package to ui package and create a Navigation.kt routing file with:

 
sealed class Navigation(val route: String) {

   object Recipes : Navigation("recipes")
   object RecipeDetails : Navigation("recipeDetails")
}

Now go to the MainScreen and add a NavHost there, replacing the RecipesScreen:

 
@Composable
public fun MainScreen() {
   val navController = rememberNavController()
   val navBackStackEntry by navController.currentBackStackEntryAsState()

   NavHost(
       navController = navController,
       startDestination = Navigation.Recipes.route, [1]
       builder = {
           composable(Navigation.Recipes.route) {
               RecipesScreen(onRecipeClicked = { [2] navController.navigate("recipeDetail/${it.id}") })
           }
           composable(
               "recipeDetail/{id}",
               arguments = listOf(navArgument("id") { type = NavType.LongType })
           ) {
               RecipeDetailsScreen( [3]
                   recipeId = it.arguments!!.getLong("id"),
                   upPress = { navController.popBackStack() })
           }
       })
}

[1] The startDestination will be the RecipesScreen
[2] We define two destinations in this piece. One is RecipesScreen, which has an onRecipeClicked callback function. It is unresolved now, but it will define the behaviour when one of the items in our RecipeList gets clicked: the navController will take us to the RecipeDetailsScreen with the recipe’s id.
[3] Another destination, RecipeDetailsScreen will receive the recipe id as an argument

Also adjust the RecipeScreen, which now has a parameter onRecipeClicked and will pass it down to the responsible component:

 
@Composable
public fun RecipesScreen(onRecipeClicked: (Recipe) -> Unit) {
  . . .
   Recipes (items = recipes, onRecipeClicked = onRecipeClicked)
}

@Composable
fun Recipes(
   items: List<Recipe>,
   onRecipeClicked: (Recipe) -> Unit
) {
   LazyColumn {
       itemsIndexed(items = items,
           itemContent = { _, item ->
               RecipeListItem(item, onRecipeClicked = onRecipeClicked)
           })

   }
}

@Composable
fun RecipeListItem(
recipe: RecipeResponse,
onRecipeClicked: (RecipeResponse) -> Unit){
. . .
   Row(
       verticalAlignment = Alignment.CenterVertically,
       modifier = Modifier
           .height(128.dp)
           .clickable { onRecipeClicked(recipe) }
   )
   . . .
}

If needed, also adjust the Preview composable:

 
@Preview
@Composable
fun RecipeListItemPreview(
) {
. . .
   RecipeListItem(recipe) {}
}

Build and run the app. Click on a recipe list item.
You’re in the RecipeDetailScreen now.

open ContentView

Now let’s go back to the recipe screen.
Wait, what?
We can’t go back - we don’t have a top bar yet!
In the next step we’ll learn how to set up a top bar with Jetpack Compose.