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.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Jetpack Compose Tutorial for Android: Getting Started
50 mins
- What Is Jetpack Compose?
- Your First Jetpack Compose App
- Hello, Android!
- A Quick Aside: What are Composable Functions?
- Back to Your First Jetpack Compose App
- Previewing a Composable
- Composable Parameters
- Your First Custom Composable Functions
- Laying Out Composables
- Introducing Compose Cookbook
- Creating a Recipe Class and Recipe Instances
- Creating a Recipe Card Composable
- Adding an Image to the Recipe Card
- Listing Ingredients
- Adding the Description
- Improving the Recipe Card’s Typography
- Adding Space to the Recipe Card
- Rounding the Recipe Card’s Corners
- Displaying the List of Recipes
- Wiring Everything Up
- Adding a Toolbar
- Making the App a Little More “Real World”
- Add a ViewModel
- Adding Methods to Change the Recipe List
- Adding UI Testing
- Where to Go From Here?
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:
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:
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:
-
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 usesText()
’sstyle
parameter to make the text it produces a little larger. -
HelloPreview()
: Provides a string and color toHello()
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:
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: