Lesson 1: Composable functions
Jetpack Compose is built around composable functions. These functions let you define your
app's UI programmatically by describing its shape and data dependencies, rather than
focusing on the process of the UI's construction. To create a composable function, just add
the @Composable
annotation to the function name.

Add a text element
To begin, follow the Jetpack Compose
setup instructions, and create an app using the Empty Compose
Activity template. The default template already contains some Compose
elements, but let's build it up step by step. First, delete the "Greeting"
and "Default Preview" functions, and delete the setContent
block from MainActivity
, leaving the activity blank. Compile
and run your blank app.
Now add a text element to your blank activity.
You do this by defining a
content block, and calling the
Text()
function.
The setContent block defines the activity's layout. Instead of defining the
layout contents with an XML file, we call composable functions. Jetpack Compose
uses a custom Kotlin compiler plugin to transform these composable functions
into the app's UI elements. For example, the
Text()
function is defined by the Compose
UI library; you call that function to declare a text element in your app.
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Text("Hello world!") } } }

Define a composable function
Composable functions can only be called from within the scope of other
composable functions. To make a function composable, add the
@Composable
annotation. To try this out, define a
Greeting()
function which is passed a
name, and uses that name to configure the text element.
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Greeting("Android") } } } @Composable fun Greeting(name: String) { Text (text = "Hello $name!") }

Preview your function in Android Studio
The current canary build of Android Studio
lets you preview
your composable functions within the IDE, instead of needing to download the
app to an Android device or emulator. The main restriction is, the composable
function must not take any parameters. For this reason, you can't preview the
Greeting()
function directly. Instead,
make a second function named
PreviewGreeting()
, which calls
Greeting()
with an appropriate parameter.
Add the @Preview
annotation before
@Composable
.
@Composable fun Greeting(name: String) { Text (text = "Hello $name!") } @Preview @Composable fun PreviewGreeting() { Greeting("Android") }

Rebuild your project. The app itself doesn't change, since the new
previewGreeting()
function isn't called
anywhere, but Android Studio adds a
preview window. This window shows a preview of the UI elements created by
composable function marked with the @Preview
annotation. To update the
previews at any time, click the refresh button at the top of the preview
window.

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Text("Hello world!") } } }

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { Greeting("Android") } } } @Composable fun Greeting(name: String) { Text (text = "Hello $name!") }

@Composable fun Greeting(name: String) { Text (text = "Hello $name!") } @Preview @Composable fun PreviewGreeting() { Greeting("Android") }


Lesson 2: Layouts
UI elements are hierarchical, with elements contained in other elements. In Compose, you build a UI hierarchy by calling composable functions from other composable functions.

Start with some Text
Go back to your activity, and replace the
Greeting()
function with a new
NewsStory()
function. For the rest
of the tutorial, you'll be modifying that
NewsStory()
function, and won't be
touching the Activity
code any more.
It's a best practice to create separate preview functions that aren't
called by the app; having dedicated preview functions improves
performance, and also makes it easier to set up multiple previews later
on. So, create a default preview function that does nothing but call the
NewsStory()
function. As you make
changes to the NewsStory()
through
this tutorial, the preview reflects the changes.
This code creates three text elements inside the content view. However, since we haven't provided any information about how to arrange them, the three text elements are drawn on top of each other, making the text unreadable.
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { NewsStory() } } } @Composable fun NewsStory() { Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } @Preview @Composable fun DefaultPreview() { NewsStory() }

Using a Column
The Column
function lets you stack
elements vertically. Add Column
to
the NewsStory()
function.
The default settings stack all the children directly, one after another, with no spacing. The column itself is put in the content view's top left corner.
@Composable fun NewsStory() { Column { Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

Add style settings to the column
By passing parameters to the Column
call, you can configure the column's size and position, and how the column's
children are arranged.
The setting has the following meaning:
modifier
: Lets you configure the layout. In this case, apply aModifier.padding
modifier, which insets the column from the surrounding view.
@Composable fun NewsStory() { Column( modifier = Modifier.padding(16.dp) ) { Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

Add a picture
We want to add a graphic above the text. Use the
Resource Manager to add this photo
to your app's drawable resources, with the name
header
.
Now modify your NewsStory()
function.
You'll add a call to Image()
to put the graphic in the
Column
. These composables are available in the `foundation` package, which you
may need to add. See Jetpack Compose
setup instructions.
The image won't be proportioned correctly, but that's okay - you'll fix that in
the next step.
@Composable fun NewsStory() { val image = imageResource(R.drawable.header) Column( modifier = Modifier.padding(16.dp) ) { Image(image) Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

The graphic is added to your layout, but it isn't sized appropriately yet.
To style the graphic, pass a size Modifier
to the call to
Image()
.
preferredHeight(180.dp)
: Specifies the height of the image.fillMaxWidth()
: Specifies that the image should be wide enough to fill the layout it belongs to.
You also need to pass a contentScale
parameter to Image()
:
contentScale = ContentScale.Crop
: Specifies that the graphic should fill the width of the column, and be cropped if necessary to the appropriate height.
@Composable fun NewsStory() { val image = imageResource(R.drawable.header) Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

Add a Spacer
to separate the graphic from the headings.
@Composable fun NewsStory() { val image = imageResource(R.drawable.header) Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { NewsStory() } } } @Composable fun NewsStory() { Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } @Preview @Composable fun DefaultPreview() { NewsStory() }

@Composable fun NewsStory() { Column { Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

@Composable fun NewsStory() { Column( modifier = Modifier.padding(16.dp) ) { Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

@Composable fun NewsStory() { val image = imageResource(R.drawable.header) Column( modifier = Modifier.padding(16.dp) ) { Image(image) Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

@Composable fun NewsStory() { val image = imageResource(R.drawable.header) Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

@Composable fun NewsStory() { val image = imageResource(R.drawable.header) Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

Lesson 3: Material design
Compose is built to support material design principles. Many of its UI elements implement material design out of the box. In this lesson, you'll style your app with material widgets.

Apply a shape
One of the pillars of the Material Design System is
Shape
. Use the
clip()
function to round the corners of the image.
The Shape
is invisible, but the graphic is cropped to fit the
Shape
, so it now has slightly rounded corners.
@Composable fun NewsStory() { val image = imageResource(R.drawable.header) Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

Style the text
Compose makes it easy to take advantage of Material Design principles. Apply
MaterialTheme
to the components you've created.
@Composable fun NewsStory() { val image = imageResource(R.drawable.header) MaterialTheme { Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } } }

The changes are subtle, but the text now uses MaterialTheme
's
default text style. Next, apply specific paragraph styles to each text
element.
@Composable fun NewsStory() { val image = imageResource(R.drawable.header) MaterialTheme { val typography = MaterialTheme.typography Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text("A day in Shark Fin Cove", style = typography.h6) Text("Davenport, California", style = typography.body2) Text("December 2018", style = typography.body2) } } }

In this case, the article's title was quite short. But sometimes an article has a long title, and we don't want the long title to throw off the app's appearance. Try changing the first text element.
@Composable fun NewsStory() { val image = imageResource(R.drawable.header) MaterialTheme { val typography = MaterialTheme.typography Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text( "A day wandering through the sandhills " + "in Shark Fin Cove, and a few of the " + "sights I saw", style = typography.h6) Text("Davenport, California", style = typography.body2) Text("December 2018", style = typography.body2) } } }

Configure the text element to set a maximum length of 2 lines. The setting has no effect if the text is short enough to fit in that limit, but the displayed text is automatically truncated if it is too long.
@Composable fun NewsStory() { val image = imageResource(R.drawable.header) MaterialTheme { val typography = MaterialTheme.typography Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text( "A day wandering through the sandhills " + "in Shark Fin Cove, and a few of the " + "sights I saw", style = typography.h6, maxLines = 2, overflow = TextOverflow.Ellipsis) Text("Davenport, California", style = typography.body2) Text("December 2018", style = typography.body2) } } }

@Composable fun NewsStory() { val image = imageResource(R.drawable.header) Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } }

@Composable fun NewsStory() { val image = imageResource(R.drawable.header) MaterialTheme { Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text("A day in Shark Fin Cove") Text("Davenport, California") Text("December 2018") } } }

@Composable fun NewsStory() { val image = imageResource(R.drawable.header) MaterialTheme { val typography = MaterialTheme.typography Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text("A day in Shark Fin Cove", style = typography.h6) Text("Davenport, California", style = typography.body2) Text("December 2018", style = typography.body2) } } }

@Composable fun NewsStory() { val image = imageResource(R.drawable.header) MaterialTheme { val typography = MaterialTheme.typography Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text( "A day wandering through the sandhills " + "in Shark Fin Cove, and a few of the " + "sights I saw", style = typography.h6) Text("Davenport, California", style = typography.body2) Text("December 2018", style = typography.body2) } } }

@Composable fun NewsStory() { val image = imageResource(R.drawable.header) MaterialTheme { val typography = MaterialTheme.typography Column( modifier = Modifier.padding(16.dp) ) { val imageModifier = Modifier .preferredHeight(180.dp) .fillMaxWidth() .clip(shape = RoundedCornerShape(4.dp)) Image(image, modifier = imageModifier, contentScale = ContentScale.Crop) Spacer(Modifier.preferredHeight(16.dp)) Text( "A day wandering through the sandhills " + "in Shark Fin Cove, and a few of the " + "sights I saw", style = typography.h6, maxLines = 2, overflow = TextOverflow.Ellipsis) Text("Davenport, California", style = typography.body2) Text("December 2018", style = typography.body2) } } }

All done
Great work! You've learned the basics of Compose.
What you've covered:
- Defining composable functions
- Using and styling columns to improve layout
- Styling your app with the Material Design principles
If you want to dig deeper on some of these steps, explore the resources below.
Continue your learning
Curated learning experience
Check out our curated pathway of codelabs and videos that will help you learn and master Jetpack Compose.
Guides and other documentation
Dive into the docs to learn more about the Jetpack Compose APIs referenced in this tutorial.
Compose by example
Get inspired with these sample apps that demonstrate how to use powerful Compose features.