Jetpack Compose makes it much easier to design and build your app's UI. Compose transforms state into UI elements, via:
- Composition of elements
- Layout of elements
- Drawing of elements
This document focuses on the layout of elements, explaining some of the building blocks Compose provides to help you lay out your UI elements.
Goals of layouts in Compose
The Jetpack Compose implementation of the layout system has two main goals:
- Ability to easily write custom layouts
Basics of composable functions
Composable functions are the basic building block of Compose. A composable function is a function emitting
@Composable fun ArtistCardColumn[] {
Column {
Text["Alfred Sisley"]
Text["3 minutes ago"]
}
}0 that describes some part of your UI. The function takes some input and generates what's shown on the screen. For more information about composables, take a look at the Compose mental model documentation.
A composable function might emit several UI elements. However, if you don't provide guidance on how they should be arranged, Compose might arrange the elements in a way you don't like. For example, this code generates two text elements:
@Composable fun ArtistCard[] {
Text["Alfred Sisley"]
Text["3 minutes ago"]
}Without guidance on how you want them arranged, Compose stacks the text elements on top of each other, making them unreadable:
Compose provides a collection of ready-to-use layouts to help you arrange your UI elements, and makes it easy to define your own, more-specialized layouts.
Standard layout components
In many cases, you can just use Compose's standard layout elements.
Use to place items vertically on the screen.
@Composable fun ArtistCardColumn[] {
Column {
Text["Alfred Sisley"]
Text["3 minutes ago"]
}
}Similarly, use to place items horizontally on the screen. Both
@Composable fun ArtistCardColumn[] {
Column {
Text["Alfred Sisley"]
Text["3 minutes ago"]
}
}1 and
@Composable fun ArtistCardColumn[] {
Column {
Text["Alfred Sisley"]
Text["3 minutes ago"]
}
}2 support configuring the alignment of the elements they contain.
@Composable fun ArtistCardRow[artist: Artist] {
Row[verticalAlignment = Alignment.CenterVertically] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column {
Text[artist.name]
Text[artist.lastSeenOnline]
}
}
}Use to put elements on top of another.
@Composable fun ArtistCardColumn[] {
Column {
Text["Alfred Sisley"]
Text["3 minutes ago"]
}
}5 also supports configuring specific alignment of the elements it contains.
@Composable fun ArtistAvatar[artist: Artist] {
Box {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Icon[Icons.Filled.Check, contentDescription = "Check mark"]
}
}Often these building blocks are all you need. You can write your own composable function to combine these layouts into a more elaborate layout that suits your app.
To set children's position within a
@Composable fun ArtistCardColumn[] {
Column {
Text["Alfred Sisley"]
Text["3 minutes ago"]
}
}2, set the
@Composable fun ArtistCardColumn[] {
Column {
Text["Alfred Sisley"]
Text["3 minutes ago"]
}
}8 and
@Composable fun ArtistCardColumn[] {
Column {
Text["Alfred Sisley"]
Text["3 minutes ago"]
}
}9 arguments. For a
@Composable fun ArtistCardColumn[] {
Column {
Text["Alfred Sisley"]
Text["3 minutes ago"]
}
}1, set the
@Composable fun ArtistCardRow[artist: Artist] {
Row[verticalAlignment = Alignment.CenterVertically] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column {
Text[artist.name]
Text[artist.lastSeenOnline]
}
}
}1 and
@Composable fun ArtistCardRow[artist: Artist] {
Row[verticalAlignment = Alignment.CenterVertically] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column {
Text[artist.name]
Text[artist.lastSeenOnline]
}
}
}2 arguments:
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}The layout model
In the layout model, the UI tree is laid out in a single pass. Each node is first asked to measure itself, then measure any children recursively, passing size constraints down the tree to children. Then, leaf nodes are sized and placed, with the resolved sizes and placement instructions passed back up the tree.
Briefly, parents measure before their children, but are sized and placed after their children.
Consider the following
@Composable fun ArtistCardRow[artist: Artist] {
Row[verticalAlignment = Alignment.CenterVertically] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column {
Text[artist.name]
Text[artist.lastSeenOnline]
}
}
}3 function.
@Composable fun SearchResult[] {
Row {
Image[
// ...
]
Column {
Text[
// ...
]
Text[
// ...
]
}
}
}This function yields the following UI tree.
SearchResult
Row
Image
Column
Text
Text
In the
@Composable fun ArtistCardRow[artist: Artist] {
Row[verticalAlignment = Alignment.CenterVertically] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column {
Text[artist.name]
Text[artist.lastSeenOnline]
}
}
}3 example, the UI tree layout follows this order:
- The root node
@Composable
fun ArtistCardColumn[] {
} 2 is asked to measure.Column { Text["Alfred Sisley"] Text["3 minutes ago"] }
- The root node
@Composable
fun ArtistCardColumn[] {
} 2 asks its first child, @Composable fun ArtistCardRow[artist: Artist] {Column { Text["Alfred Sisley"] Text["3 minutes ago"] }
} 7, to measure.Row[verticalAlignment = Alignment.CenterVertically] { Image[bitmap = artist.image, contentDescription = "Artist image"] Column { Text[artist.name] Text[artist.lastSeenOnline] } }
- @Composable
fun ArtistCardRow[artist: Artist] {
} 7 is a leaf node [that is, it has no children], so it reports a size and returns placement instructions.Row[verticalAlignment = Alignment.CenterVertically] { Image[bitmap = artist.image, contentDescription = "Artist image"] Column { Text[artist.name] Text[artist.lastSeenOnline] } }
- The root node
@Composable
fun ArtistCardColumn[] {
} 2 asks its second child, @Composable fun ArtistCardColumn[] {Column { Text["Alfred Sisley"] Text["3 minutes ago"] }
} 1, to measure.Column { Text["Alfred Sisley"] Text["3 minutes ago"] }
- The
@Composable
fun ArtistCardColumn[] {
} 1 node asks its first @Composable fun ArtistAvatar[artist: Artist] {Column { Text["Alfred Sisley"] Text["3 minutes ago"] }
} 2 child to measure.Box { Image[bitmap = artist.image, contentDescription = "Artist image"] Icon[Icons.Filled.Check, contentDescription = "Check mark"] }
- The first
@Composable
fun ArtistAvatar[artist: Artist] {
} 2 node is a leaf node, so it reports a size and returns placement instructions.Box { Image[bitmap = artist.image, contentDescription = "Artist image"] Icon[Icons.Filled.Check, contentDescription = "Check mark"] }
- The
@Composable
fun ArtistCardColumn[] {
} 1 node asks its second @Composable fun ArtistAvatar[artist: Artist] {Column { Text["Alfred Sisley"] Text["3 minutes ago"] }
} 2 child to measure.Box { Image[bitmap = artist.image, contentDescription = "Artist image"] Icon[Icons.Filled.Check, contentDescription = "Check mark"] }
- The second
@Composable
fun ArtistAvatar[artist: Artist] {
} 2 node is a leaf node, so it reports a size and returns placement instructions.Box { Image[bitmap = artist.image, contentDescription = "Artist image"] Icon[Icons.Filled.Check, contentDescription = "Check mark"] }
- Now that the
@Composable
fun ArtistCardColumn[] {
} 1 node has measured, sized, and, placed its children, it can determine its own size and placement.Column { Text["Alfred Sisley"] Text["3 minutes ago"] }
- Now that the root node
@Composable
fun ArtistCardColumn[] {
} 2 has measured, sized, and placed its children, it can determine its own size and placement.Column { Text["Alfred Sisley"] Text["3 minutes ago"] }
Performance
Compose achieves high performance by measuring children only once. Single-pass measurement is good for performance, allowing Compose to efficiently handle deep UI trees. If an element measured its child twice and that child measured each of its children twice and so on, a single attempt to lay out a whole UI would have to do a lot of work, making it hard to keep your app performant.
If your layout needs multiple measurements for some reason, Compose offers a special system, intrinsic measurements. You can read more about this feature in Intrinsic measurements in Compose layouts.
Since measurement and placement are distinct sub-phases of the layout pass, any changes that only affects placement of items, not measurement, can be executed separately.
Using modifiers in your layouts
As discussed in Compose modifiers, you can use modifiers to decorate or augment your composables. Modifiers are essential for customizing your layout. For example, here we chain several modifiers to customize the
@Composable fun ArtistAvatar[artist: Artist] {
Box {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Icon[Icons.Filled.Check, contentDescription = "Check mark"]
}
}9:
@Composable fun ArtistCardModifiers[
artist: Artist,
onClick: [] -> Unit
] {val padding = 16.dp
Column[
Modifier
.clickable[onClick = onClick]
.padding[padding]
.fillMaxWidth[]
] {
Row[verticalAlignment = Alignment.CenterVertically] { /*...*/ }
Spacer[Modifier.size[padding]]
Card[
elevation = CardDefaults.cardElevation[defaultElevation = 4.dp],
] { /*...*/ }
}
}In the code above, notice different modifier functions used together.
- @Composable
fun ArtistCardArrangement[artist: Artist] {
} 0 makes a composable react to user input and shows a ripple.Row[ verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ] { Image[bitmap = artist.image, contentDescription = "Artist image"] Column { /.../ } }
- @Composable
fun ArtistCardArrangement[artist: Artist] {
} 1 puts space around an element.Row[ verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ] { Image[bitmap = artist.image, contentDescription = "Artist image"] Column { /.../ } }
- @Composable
fun ArtistCardArrangement[artist: Artist] {
} 2 makes the composable fill the maximum width given to it from its parent.Row[ verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ] { Image[bitmap = artist.image, contentDescription = "Artist image"] Column { /.../ } }
- @Composable
fun ArtistCardArrangement[artist: Artist] {
} 3 specifies an element's preferred width and height.Row[ verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.End ] { Image[bitmap = artist.image, contentDescription = "Artist image"] Column { /.../ } }
Learn more about scrollable layouts in the Compose gestures documentation.
For lists and lazy lists, check out the Compose lists documentation.
Responsive layouts
A layout should be designed with consideration of different screen orientations and form factor sizes. Compose offers out of the box a few mechanisms to facilitate adapting your composable layouts to various screen configurations.
Constraints
In order to know the constraints coming from the parent and design the layout accordingly, you can use a
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}4. The measurement constraints can be found in the scope of the content lambda. You can use these measurement constraints to compose different layouts for different screen configurations:
@Composable fun WithConstraintsComposable[] {
BoxWithConstraints {
Text["My minHeight is $minHeight while my maxWidth is $maxWidth"]
}
}Slot-based layouts
Compose provides a large variety of composables based on Material Design with the
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}5 dependency [included when creating a Compose project in Android Studio] to make UI building easy. Elements like
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}6,
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}7, and
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}8 are all provided.
Material components make heavy use of slot APIs, a pattern Compose introduces to bring in a layer of customization on top of composables. This approach makes components more flexible, as they accept a child element which can configure itself rather than having to expose every configuration parameter of the child. Slots leave an empty space in the UI for the developer to fill as they wish. For example, these are the slots that you can customize in a
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}8:
Composables usually take a
@Composable fun SearchResult[] {
Row {
Image[
// ...
]
Column {
Text[
// ...
]
Text[
// ...
]
}
}
}0 composable lambda [
@Composable fun SearchResult[] {
Row {
Image[
// ...
]
Column {
Text[
// ...
]
Text[
// ...
]
}
}
}1]. Slot APIs expose multiple
@Composable fun SearchResult[] {
Row {
Image[
// ...
]
Column {
Text[
// ...
]
Text[
// ...
]
}
}
}0 parameters for specific uses. For example,
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}8 allows you to provide the content for
@Composable fun SearchResult[] {
Row {
Image[
// ...
]
Column {
Text[
// ...
]
Text[
// ...
]
}
}
}4,
@Composable fun SearchResult[] {
Row {
Image[
// ...
]
Column {
Text[
// ...
]
Text[
// ...
]
}
}
}5, and
@Composable fun SearchResult[] {
Row {
Image[
// ...
]
Column {
Text[
// ...
]
Text[
// ...
]
}
}
}6.
For example, allows you to implement a UI with the basic Material Design layout structure.
@Composable fun SearchResult[] {
Row {
Image[
// ...
]
Column {
Text[
// ...
]
Text[
// ...
]
}
}
}7provides slots for the most common top-level Material components, such as
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}8,
SearchResult
Row
Image
Column
Text
Text
0,
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}7, and
@Composable fun ArtistCardArrangement[artist: Artist] {
Row[
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
] {
Image[bitmap = artist.image, contentDescription = "Artist image"]
Column { /*...*/ }
}
}6. By using
@Composable fun SearchResult[] {
Row {
Image[
// ...
]
Column {
Text[
// ...
]
Text[
// ...
]
}
}
}7, it's easy to make sure these components are properly positioned and work together correctly.
How to use one layout in another layout in Android Studio?
Reuse layouts with Although Android offers a variety of widgets to provide small, reusable, interactive elements, you might also need to reuse larger components that require a special layout. To efficiently reuse complete layouts, use the and tags to embed one layout inside another.
What is nested layout in Android Studio?
By the term of Nested we mean one Layout inside of other Layout. In Android all layout can be nested one another.
How to arrange layout in Android Studio?
Click the Design button in the top-right corner of the editor window. In the Component Tree, right-click the view or layout, and then click Convert view. In the dialog that appears, choose the new type of view or layout, and then click Apply.
How to add horizontal layout in Android Studio?
To create a linear layout in which each child uses the same amount of space on the screen, set the android:layout_height of each view to "0dp" for a vertical layout, or the android:layout_width of each view to "0dp" for a horizontal layout. Then set the android:layout_weight of each view to "1" .