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
Columnto place items vertically on the screen. - Use
Rowto place items horizontally on the screen. - Use
Boxto 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:
@Composablefun 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:
@Composablefun ModifierExample() { Text( text = "Hello with padding", modifier = Modifier.padding(16.dp) )}Chaining modifiers
Modifiers can be chained together to apply multiple effects:
@Composableprivate 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:
@Composablefun 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:
@Composablefun 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:
@Composablefun 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:
@Composablefun MatchParentSizeComposable() { Box { // Takes size of its parent Box Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) // The largest child, determines the Box size Card() }}