Jetpack Compose Tutorial for Android: Getting Started

In this Jetpack Compose tutorial, you’ll learn to use the new declarative UI framework being developed by the Android team by creating a cookbook app. By Joey deVilla.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 6 of this article. Click here to view the first page.

Introducing Compose Cookbook

With your first Jetpack Compose project complete, let’s create one that looks a little more like a full-fledged app. It’s called Compose Cookbook and it displays a list of recipe cards, each one featuring a photo, the recipe’s name, a list of ingredients and a description. When complete, it’ll look like this:

Begin by clicking the Download Materials link at the top or bottom of this page to download a .zip file containing the starter, intermediate, and final versions of the Compose Cookbook project. Open the starter project (it’s in the starter folder) in Android Studio.

The starter project is Android Studio’s Empty Activity Jetpack Compose project with images of food in different resolutions in the project’s drawable resource directories. Peruse them, but don’t blame us if they make you hungry and stop for a snack!

If you build and run the app now, all you’ll see is the default “Hello Android!” screen. It’s time to make the app more interesting!

Creating a Recipe Class and Recipe Instances

This app is a cookbook, which is a collection of recipes. Each recipe will display to the user like this:

Ramen recipe card

The first step is to create a data type for storing the various parts of a recipe. For this app, these are:

  • Photo
  • Title
  • List of ingredients
  • Description

A data class should do the job nicely. Create a file for this class — right-click on the composecookbook package, select New ▸ New Kotlin Class/File, select Class from the list and name the class Recipe.

Replace the empty Recipe class with the following:

import androidx.annotation.DrawableRes

data class Recipe(
 @DrawableRes val imageResource: Int,
 val title: String,
 val ingredients: List<String>,
 val description: String
)

Now that there’s a data type for recipes, it’s time to create some recipe instances. They’ll be defined in a new file, so right-click on the composecookbook package, select New ▸ New Kotlin Class/File, selecting File from the list and name the file Recipes.

Add the following declaration to the file:

val defaultRecipes = listOf(
  Recipe(
    imageResource = R.drawable.noodles,
    title = "Ramen",
    ingredients = listOf("Noodles", "Eggs", "Mushrooms", "Carrots", "Soy sauce"),
    description = "Japan’s famous noodles-and-broth dish. It’s meant to be slurped LOUDLY."
  ),
  Recipe(
    imageResource = R.drawable.croissant,
    title = "Croissant",
    ingredients = listOf("Butter", "More butter", "A touch of butter", "Flour"),
    description = "This French pastry is packed with butter and cholesterol, as the best foods are."
  ),
  Recipe(
    imageResource = R.drawable.pizza,
    title = "Pizza",
    ingredients = listOf("Pizza dough", "Tomatoes", "Cheese", "Spinach", "Love"),
    description = "The official food of late-night coding sessions. Millions of programmers can’t be wrong!"
  ),
  Recipe(
    imageResource = R.drawable.produce,
    title = "Veggie Medley",
    ingredients = listOf("Vegetables"),
    description = "We had to put something healthy on the menu..."
  ),
  Recipe(
   imageResource = R.drawable.salad_egg,
   title = "Egg Salad",
   ingredients = listOf("Eggs", "Mayonnaise", "Paprika", "Mustard"),
   description = "It’s really just eggs in tasty, creamy goo. The vegetables in the photo are just for show."
  ),
  Recipe(
   imageResource = R.drawable.smoothie,
   title= "Fruit Smoothie",
   ingredients = listOf("Banana", "Kiwi", "Milk", "Cream", "Ice", "Flax seed"),
   description = "The healthy version of a milkshake. We’ll have a REAL milkshake later."
  )
)

The code you just entered creates defaultRecipes, a list of Recipe instances. You’ll eventually write a composable that will use this list to create the recipe cards that the app will display.

You now have a collection of recipes — it’s time to work on the code to display them.

Creating a Recipe Card Composable

Right-click on the composecookbook package, select New ▸ New Kotlin Class/File, select File from the list, and name the file RecipeCard. This will create a file for the composable that emits the recipe card and a preview composable that allows you to see what the recipe card will look like as you code it.

Add a new composable, RecipeCard() to the file. Here’s its code:

@Composable
fun RecipeCard(recipe: Recipe) {
  Text(recipe.title)
}

Given a Recipe object, this composable will emit a text view containing the recipe’s title.

It would be helpful to see what the recipe card looks like as you code it, so it’s time to write a preview composable that makes use of RecipeCard(). Add this composable just below RecipeCard():

@Composable
@Preview
fun RecipeCardPreview() {
  RecipeCard(defaultRecipes[0])
}

RecipeCard() has a parameter, so in order to call it, RecipeCardPreview() needs to provide a corresponding argument. The project has a list of recipes, defaultRecipes (defined in Recipes.kt, so the RecipeCardPreview() uses the first recipe in the list, Ramen, for the preview.

You can now preview the recipe card:

A preview of the recipe card, which simply displays the title, Ramen.

That takes care of the first of four properties that make up a recipe object. The next step is to draw an image above the title.

Adding an Image to the Recipe Card

Update RecipeCard() to the following:

@Composable
fun RecipeCard(recipe: Recipe) {
 // 1
  Column(modifier = Modifier.fillMaxWidth()) {
   // 2
    Image(
      painterResource(recipe.imageResource),
      contentDescription = recipe.title,
      contentScale = ContentScale.Crop,
      modifier = Modifier.fillMaxWidth().height(144.dp)
    )
    Text(recipe.title)
  }
}

You’ll see lots of red text denoting unresolved references, so ensure that you import them (their names will all begin with androidx.compose.

There’s a lot of magic going on in such a tiny chunk of code. Here’s what’s happening in it (the numbers below match the numbered comments in the code above):

  1. The image should appear above the title, so this is a good place to use a Column. The lambda passed to Column makes a call to Image() first, followed by Text(), which puts the image above the title. The call to Column includes a modifier argument that ensures the column expands to the width of its containing view.
  2. The Image composable, as its name suggests, draws the image for the recipe. Recipe instances have an imageResource property that points to a Drawable in the project’s res folder. The code also provides the recipe title as an argument for contentDescription to make it a little more useful to users who use accessibility features, and it uses the contentScale and modifier parameters to ensure the image takes up the width of the card but is cropped to limit its height.

Refresh the preview and you’ll see your recipe card taking shape.

A preview of the recipe card, which displays the image of the recipe and the title.

The next step is to display the ingredients.