Layouts and UI in Android with Jetpack Compose
Layouts and UI in Android with Jetpack Compose
In Jetpack Compose, you arrange UI with three core containers: Column stacks items vertically, Row places them horizontally, and Box layers items on top of each other. You control size, spacing, padding, and behaviour with modifiers. For long, scrollable lists you use LazyColumn. Master these five ideas and you can lay out almost any screen.
The Three Containers
Column and Row
Column puts children top to bottom; Row puts them left to right. You control how children are spaced with verticalArrangement / horizontalArrangement, and how they align on the cross axis with the alignment parameters.
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun ProfileHeader() {
// Column stacks the two rows vertically
Column(
modifier = Modifier.fillMaxWidth().padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp) // gap between children
) {
Text(text = "Asha Patil")
// Row places these two pieces of text side by side
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth()
) {
Text(text = "Roll No: 12")
Text(text = "Class: 10A")
}
}
}
Box
Box stacks children on top of each other, useful for overlays such as a badge on an avatar or text over an image. You position children with Modifier.align(...).
Modifiers: The Way You Style and Size
A modifier is a chainable instruction that changes how a composable looks or behaves: its size, padding, background, click handling, and more. Order matters: padding applied before a background fills differently than padding applied after.
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
@Composable
fun Tag() {
Text(
text = "New",
// modifiers are read top to bottom: background first, then inner padding
modifier = Modifier
.background(Color(0xFF2E7D32))
.padding(horizontal = 12.dp, vertical = 4.dp)
)
}
Want to learn this properly?
Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.
Browse coursesSpacing and Sizing
fillMaxWidth()/fillMaxSize()make a composable take all available width or space.size(48.dp)sets a fixed size in density-independent pixels (dp).padding(16.dp)adds breathing room.Arrangement.spacedBy(8.dp)puts even gaps between children in a Column or Row.
Use dp for sizes and spacing, and sp for text so it respects the user's font-size preference.
Long Lists: Use LazyColumn
A normal Column lays out all children at once, which is wasteful for hundreds of items. LazyColumn only composes the items currently on screen, scrolling efficiently.
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@Composable
fun StudentList(names: List<String>) {
// LazyColumn renders only visible rows, so big lists stay smooth
LazyColumn {
items(names) { name -> // one row per name
Text(
text = name,
modifier = Modifier.padding(12.dp)
)
}
}
}
Common Mistakes
- Using a plain Column for long lists. It builds every item up front and can stutter or run out of memory. Use
LazyColumn. - Confusing arrangement and alignment. Arrangement controls spacing along the main axis; alignment controls position on the cross axis. Mixing them up gives unexpected layouts.
- Ignoring modifier order.
padding().background()andbackground().padding()look different. Think about the order. - Using pixels instead of dp/sp. Hard-coded pixels do not scale across devices. Use
dpfor sizes andspfor text. - Forgetting
fillMaxWidth()on a Row when you expectSpaceBetweento push children apart. Without it the Row only wraps its content.
FAQ
When should I use Box instead of Column? Use Box when items overlap or layer, like a label on top of an image. Use Column or Row when items sit beside each other.
What is the difference between dp and sp?
dp is for layout sizes and scales with screen density. sp is for text and also respects the user's chosen font scale.
Do I still need XML layouts? For new Compose projects, no. XML is the older system you may meet in legacy code.
Keep Going
Now that you can lay out a screen, learn to move between screens in Activities and Navigation, or revisit the basics in Build Your First Android App. See the full path at the Android learning hub.
Want hands-on layout practice with feedback? Join the waitlist for the Android Development course at Infoplanet in Jalgaon.
Want to learn this properly?
Join the waitlist for our courses — beginner-friendly, project-first classes in Jalgaon.
Browse coursesFounder, Infoplanet
Atul Kabra founded Infoplanet in 2001 and has spent over two decades teaching programming — C, C++, Java, databases and more — to students across Maharashtra.
Related guides
Activities and Navigation in Android
What an activity is, how its lifecycle works, and how to move between screens cleanly using Navigation Compose, including passing arguments between destinations.
Calling an API in Android with Retrofit and Coroutines
How to call a REST API from an Android app using Retrofit and Kotlin coroutines: declare the endpoint, model the JSON, run the call off the main thread, and handle errors.
Permissions in Android: Requesting Access the Right Way
How Android permissions work: the difference between install-time and runtime (dangerous) permissions, declaring them in the manifest, and requesting them politely in Compose.
