Compose - Layout

To effectively build user interfaces, it's important to understand the key concepts of layout construction, including core principles, layout phases, and common components and tools available for structuring your UI.

Column, Row, and Box

To structure your layouts, you can use these basic building blocks:

  • Use Column to place items vertically on the screen.
  • Use Row to place items horizontally on the screen.
  • Use Box to stack elements on top of each other.

Use the FlowRow and FlowColumn versions of Row and Column to build responsive layouts. Items automatically flow into the next line when the container runs out of space, creating multiple rows or columns:

@Composable
fun ResponsiveLayout() {
FlowRow {
Text(text = "Item 1")
Text(text = "Item 2")
Text(text = "Item 3")
}
}

Modifiers

Modifiers allow you to decorate or adjust the behavior of composables declaratively. They are essential for customizing layouts and interactions by providing control over dimensions, alignment, padding, interaction behaviors, and much more.

For example, you can add padding and center alignment to text:

@Composable
fun ModifierExample() {
Text(
text = "Hello with padding",
modifier = Modifier.padding(16.dp)
)
}

Chaining modifiers

Modifiers can be chained together to apply multiple effects:

@Composable
private fun Greeting(name: String) {
Column(
// Chained `Modifier` functions:
modifier = Modifier
// `Modifier.padding(24.dp)` adds padding around the column
.padding(24.dp)
// `Modifier.fillMaxWidth()` makes the column expand to fill the available width
.fillMaxWidth()
) {
Text(text = "Hello,")
Text(text = name)
}
}

The order of modifier functions in the chain is significant. Each function makes changes to the Modifier returned by the previous function, so the sequence of calls directly affects the composable’s final behavior and appearance.

Built-in modifiers

Compose provides built-in modifiers, such as size, padding, and offset, for handling common layout and positioning tasks.

Size modifiers

To set a fixed size, use the size modifier. When constraints need to be overridden, use the requiredSize modifier:

@Composable
fun Card() {
// Sets the row size to 400x100 dp
Row(modifier = Modifier.size(width = 400.dp, height = 100.dp)
) {
Image(
// Sets the required size to 150x150 dp and overrides the parent`s 100 dp limit
modifier = Modifier.requiredSize(150.dp)
)
Column {
// The content takes the remaining space within the row
}
}
}

Padding modifiers

Add padding around an element with the padding modifier.

You can also apply padding dynamically in relation to baselines using paddingFromBaseline:

@Composable
fun Card() {
Row {
Column {
// Applies padding to adjust the position relative to the baseline
Text(
text = "Title",
modifier = Modifier.paddingFromBaseline(top = 50.dp)
)
// Follows the default arrangement as there is no padding specified
Text(text = "Subtitle")
}
}
}

Offset modifiers

To adjust the position of a layout from its original position, use the offset modifier.

Specify the offset in the X and Y axes:

@Composable
fun Card() {
Row {
Column {
// Positions the text normally with no offsets applied
Text(text = "Title")
// Moves the text slightly to the right with the 4.dp offset along the X-axis,
// while keeping the original vertical position
Text(
text = "Subtitle",
modifier = Modifier.offset(x = 4.dp)
)
}
}
}

Scoped modifiers

Scoped modifiers, also called parent data modifiers, notify the parent layout of specific requirements for a child.

For example, to match the size of a parent Box, use the matchParentSize modifier:

@Composable
fun MatchParentSizeComposable() {
Box {
// Takes size of its parent Box
Spacer(
Modifier
.matchParentSize()
.background(Color.LightGray)
)
// The largest child, determines the Box size
Card()
}
}

Keep Reading - Modifiers

Code Lab

Basic layouts in Compose

Pending