Compose Multi-Platform Layout Principles
Layout via Containers
Elements are laid out in Compose using containers . The key containers are:
Row to place child elements horizontally, side-by-side
Column to place child elements in a vertical stack
Box to place child elements overlapping each other
No Layout
Hello
World
from
Kotlin
Compose!
This window contains several Text elements.
Without any indication of how to layout the elements, the window simple stacks them all on top of each other in the top-left corner.
fun main() = singleWindowApplication(
title = "No Layout"
) {
App()
}
@Composable
fun App() {
Text("Hello")
Text("World")
Text("from")
Text("Kotlin")
Text("Compose!")
}
Row: Horizontal Flow
Hello
World
from
Kotlin
Compose!
We can specifiy that we want the Text elements to sit horizontally, side-by-side by placing them into a Row layout container
fun main() = singleWindowApplication(
title = "Horizontal"
) {
App()
}
@Composable
fun App() {
Row() {
Text("Hello")
Text("World")
Text("from")
Text("Kotlin")
Text("Compose!")
}
}
Column: Vertical Stack
Hello
World
from
Kotlin
Compose!
We can specifiy that we want the Text elements to stack up vertically, one above the other by placing them into a Column layout container
fun main() = singleWindowApplication(
title = "Vertical"
) {
App()
}
@Composable
fun App() {
Column() {
Text("Hello")
Text("World")
Text("from")
Text("Kotlin")
Text("Compose!")
}
}
Grid: Rows in Columns
Hello
World
from
Kotlin
Compose!
To layout our Text elements in a grid that flows from left-to-right, we can create a Column with multiple, nested Row layout containers
fun main() = singleWindowApplication(
title = "Rows in Columns"
) {
App()
}
@Composable
fun App() {
Column() {
Row() {
Text("Hello")
Text("World")
Text("from")
}
Row() {
Text("Kotlin")
Text("Compose!")
}
}
}
Grid: Columns in Rows
Hello
World
from
Kotlin
Compose!
Similarly, to layout our Text elements in a grid that flows from top-to-bottom, we can create a Row with multiple, nested Column layout containers
fun main() = singleWindowApplication(
title = "Columns in Rows"
) {
App()
}
@Composable
fun App() {
Row() {
Column() {
Text("Hello")
Text("World")
Text("from")
}
Column() {
Text("Kotlin")
Text("Compose!")
}
}
}
Box: Overlapping
Hello
World
from
Kotlin
Compose!
To layout our Text elements so they overlap eachother (useful for placing images behind elements, for example), we can create a Box layout container
fun main() = singleWindowApplication(
title = "Box Layout"
) {
App()
}
@Composable
fun App() {
Box() {
Image(
painter = painterResource("images/compose.png"),
contentDescription = "Compose logo"
)
Column() {
Text("Hello")
Text("World")
Text("from")
Text("Kotlin")
Text("Compose!")
}
}
}
Example Layout 1
Jean-Paul Williams
UX Designer
Demo Corp.
A Row with a nested Column allows images and text elements to be laid out next to each other.
fun main() = singleWindowApplication(
title = "User Info"
) {
App()
}
@Composable
fun App() {
Row() {
Image(
painter = painterResource("images/avatar.png"),
contentDescription = "User avatar"
)
Column() {
Text("Jean-Paul Williams")
Text("UX Designer")
Text("Demo Corp.")
}
}
}
Example Layout 2
Jean-Paul Williams
UX Designer
Demo Corp.
Send Message
An outer Column container with nested Row and Column containers within can produce quite complex layouts.
fun main() = singleWindowApplication(
title = "Message User"
) {
App()
}
@Composable
fun App() {
Column() {
Row() {
Image(
painter = painterResource("images/avatar.png"),
contentDescription = "User avatar"
)
Column() {
Text("Jean-Paul Williams")
Text("UX Designer")
Text("Demo Corp.")
}
}
OutlinedTextField(
label = { Text("Message") },
value = "",
onValueChange = {}
)
Button(
onClick = {...}
) {
Text("Send Message")
}
}
}
Custom Composable Elements
Helen Pickles
Managing Director
Demo Corp.
Jean-Paul Williams
UX Designer
Demo Corp.
In order to keep your main App() function compact and easy to read / maintain , or if part of your UI layout is to be repeated , it is a good idea to define custom @Composable elements you can then use within your main layout.
You can pass data as arguments to a composable element that it can then use to create part of the UI...
fun main() = singleWindowApplication(
title = "Who Are We?"
) {
App()
}
@Composable
fun App() {
Column() {
StaffCard(helen)
StaffCard(jeanpaul)
}
}
@Composable
fun StaffCard(staff: Employee) = Row() {
Image(
painter = painterResource("images/${staff.avatar}"),
contentDescription = "${staff.name} avatar"
)
Column() {
Text(staff.name)
Text(staff.role)
Text("Demo Corp.")
}
}
Example Layout 3
9876543210
7
4
1
0
8
5
2
•
9
6
3
=
÷
×
–
+
Several Row and Column layout containers are nested within each other to position and align the UI elements for this calculator.
fun main() = singleWindowApplication(
title = "Calculator"
) {
App()
}
@Composable
fun App() {
Column() {
Text("9876543210")
Row() {
Column() {
Button(...) { Text("7") }
Button(...) { Text("4") }
Button(...) { Text("1") }
Button(...) { Text("0") }
}
Column() {
Button(...) { Text("8") }
Button(...) { Text("5") }
Button(...) { Text("2") }
Button(...) { Text(".") }
}
Column() {
Button(...) { Text("9") }
Button(...) { Text("6") }
Button(...) { Text("3") }
Button(...) { Text("=") }
}
Column() {
Button(...) { Text("÷") }
Button(...) { Text("×") }
Button(...) { Text("–") }
Button(...) { Text("+") }
}
}
}
}
Note that these examples have spacing added around elements to help show how the layouts work. The code snippets don't apply the same spacing. Also note that other layout containers are available in Compose (e.g. Box ). However, for most layouts, Row and Column suffice.