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 2 of 6 of this article. Click here to view the first page.

A Quick Aside: What are Composable Functions?

Composable functions, also called composables, are the building blocks of Jetpack Compose. While they’re not the same as views from Views (remember, it’s the new name for the old way of building Android apps), they fill the same roles and behave similarly. They act as user interface elements or containers for user interface elements, just as views do in traditional Android projects. Think of them as functions that take in data to create UI elements.

In mathematics, when you take the result of a function f() and feed it to another function g(), you are composing the two functions into a new function h(), whose value is g(f()). You first compute the value of f() and feed its result to g() to get the final result. In Jetpack Compose, we do something similar — you can feed the UI component that one composable generates into another composable to create a more complex UI component. You do this by nesting composables inside other composables.

Back to Your First Jetpack Compose App

At the moment, the code uses only one of Greeting()’s two parameters. Make use of the other parameter, modifier, by updating the call to Greeting() in onCreate() to the following:

Greeting(
 name = "Android",
 modifier = Modifier
   .padding(20.dp)
   .blur(3.dp)
)

Note that the new call to Greeting() uses Kotlin’s named argument syntax and is formatted to that each argument on its own line. You’ll see that many Jetpack Compose apps are written this way because it makes complex layouts easier to read and update.

Build and run the app:

Android phone emulator displaying Hello Android!, but padded and blurred

The modifier parameter allows you to pass a Modifier object and one or more calls to its methods, which allow you to modify the appearance of a UI element. In this case, you’re telling Greeting() to apply 20 device-independent pixels of padding and three device-independent pixels of blur to the UI element that it emits.

Before you continue, remove the modifier argument from the call to Greeting() so it looks like this:

Greeting(
 name = "Android"
)

Previewing a Composable

Normally, when you create the UI for one of your activities in XML, you use the layout preview to see how your view will look without building and running your app. Jetpack Compose does this with preview composables.

Take a look at GreetingPreview(), which immediately follows Greeting():

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
  MyFirstComposeAppTheme {
    Greeting("Android")
  }
}

As implied by both its name and its @Preview annotation, its purpose is to generate a preview of the output of Greeting() in the preview pane:

Note: If you don’t see the preview pane, click the Split selector at the upper right of the code pane.

The @Preview annotation tells the compiler that this composable creates a UI element or container that doesn’t appear in the running app, but instead is rendered in Android Studio’s preview pane. Android Studio watches the code in @Preview composables and updates the Preview pane.

To see this updating in action, change the Greeting() call in GreetingPreview() to the following:

Greeting("There")

In short order, the content of the text view in the preview pane will change to “Hello There!”

Composable Parameters

Hold the cursor over the call to Text() inside the Greeting() method. The pop-up that appears will show that Text() has many parameters. Use the color parameter by updating the call to Text() to this:

 Text(
   text = "Hello $name!",
   modifier = modifier,
   color = Color.Red
 )

You’ll see that the text in the preview and the app (when you run it) is now red.

If you’ve followed all the steps in the tutorial, the text in the preview pane will read “Hello There!” while the text displayed by the running app will read “Hello Android!” To use an old programmer cliché, this isn’t a bug, but a feature. This demonstrates how preview composables can use test data, which allows you to see what a UI element would look like without requiring any real data that the program would use. You’ll see how useful this feature is later in this tutorial.

Your First Custom Composable Functions

Replace Greeting() and GreetingPreview() with the following:

@Composable
fun Hello(name: String, modifier: Modifier = Modifier, color: Color = Color.Black) {
 Text(
   text = "Hello $name!",
   modifier = modifier,
   color = color,
   style = MaterialTheme.typography.headlineMedium
 )
}

@Preview(showBackground = true)
@Composable
fun HelloPreview() {
 MyFirstComposeAppTheme {
   Hello(
     name = "There",
     color = Color.Magenta
   )
 }
}

You’ve just replaced Greeting() and its preview counterpart GreetingPreview() with these methods:

  1. Hello(): Receives a string, modifier and color and emits a text view displaying the given string in the app, applying the given modifier and color while doing so. It uses Text()’s style parameter to make the text it produces a little larger.
  2. HelloPreview(): Provides a string and color to Hello() and emits a text view displaying the given string in the preview, applying the given color while doing so.

Congratulations — you’ve created your first custom composable functions! The preview pane should automatically update …

… but the app won’t work until you replace the call to Greeting() in onCreate() with a call to Hello():

Hello(
 name = "Blue Android",
 color = Color.Blue
)

Build and run the app. It should now display “Hello Blue Android!” in blue text.

Laying Out Composables

Having only one text view on the screen doesn’t make for a particularly interesting app. However, having three of them should make for a riveting experience! :]

Update onCreate() so it calls Hello() three times, using a different string and color each time:

Hello(
 name = "Blue Android",
 color = Color.Blue
)
Hello(
 name = "Red Android",
 color = Color.Red
)
Hello(
 name = "Green Android",
 color = Color.Green
)

How would you expect this composable to look? Build and run, then take a look in the preview window to see whether the results match your expectations:

Hello Blue Android, Hello Red Android, and Hello Green Android, all piled on top of each other

That’s probably not the outcome you were hoping for. Right now, nothing is governing the positioning of the text views, which is why they’re piled on top of each other.

Fortunately, Jetpack Compose provides a collection of layout composables — composable functions that emit UI elements that act as containers for laying out other UI elements. One such composable is Column, which acts like a LinearLayout with its orientation parameter set to vertical.

In onCreate(), wrap the three calls to Hello() in a call to Column():

Column {
 Hello(
   name = "Blue Android",
   color = Color.Blue
 )
 Hello(
   name = "Red Android",
   color = Color.Red
 )
 Hello(
   name = "Green Android",
   color = Color.Green
 )
}

Take note of how you’re using Column{}: You’re passing it a lambda containing calls to composables. In other words, you’re passing it a function made of other functions, or as a mathematician would say, you’re composing functions! That’s where the “Compose” in Jetpack Compose comes from.

Build and run the app. You should see this:

Hello Blue Android, Hello Red Android, and Hello Green Android, neatly laid out in a column