Episode ini menguasai blok layout dasar Compose: Column, Row, Box, LazyColumn, dan LazyRow, komponen Material 3 seperti Button, TextField, dan Card, sistem Modifier untuk spacing dan alignment, serta strategi responsive layout.

Project kalian sudah berdiri dan composable pertama sudah berjalan. Sekarang saatnya menyusun layar yang sesungguhnya. Episode 4 membekali kalian dengan building blocks layout Compose: Column, Row, Box, dan koleksi Lazy, plus komponen Material 3.
Kunci kelancaran di sini adalah memahami Modifier. Hampir semua aspek visual — jarak, ukuran, posisi, klik — diatur lewat modifier, bukan lewat atribut XML seperti dulu. Sekali kalian menguasai Modifier, membaca layout orang lain menjadi mudah.
Episode 4 ini meliputi core layout composables, komponen Material, sistem Modifier, dan responsive layout.
Tiga layout dasar ini menyusun 90 persen screen kalian: Column menumpuk anak secara vertikal, Row menyusun horizontal, dan Box menumpuk elemen di atas satu sama lain.
@Composable
fun ProfilSingkat() {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Arman Dwi", style = MaterialTheme.typography.titleLarge)
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
Button(onClick = { }) { Text("Ikuti") }
OutlinedButton(onClick = { }) { Text("Pesan") }
}
Box(
modifier = Modifier
.size(64.dp)
.background(MaterialTheme.colorScheme.primary)
) {
Text("logo", Modifier.align(Alignment.Center))
}
}
}Arrangement.spacedBy(8.dp) memberi jarak konsisten antar anak, dan Alignment menempatkan posisi. Di Box, Modifier.align(Alignment.Center) menempatkan teks di tengah kotak — pola umum untuk badge dan overlay.
Untuk daftar panjang, gunakan LazyColumn (vertikal) dan LazyRow (horizontal). Keduanya hanya merender item yang terlihat — efisiensi yang tidak dimiliki Column biasa. Detail lazy list akan dibahas mendalam di episode 9.
LazyColumn {
items(20) { index ->
ListItem(
headlineContent = { Text("Item ke-$index") }
)
}
}items(20) menciptakan item secara lazy berdasarkan indeks. Saat daftar bertambah besar, kalian akan memakai items dengan list data dan key (episode 9 dan 15).
Material 3 menyediakan varian Button, Text, dan input teks yang langsung memakai theme kalian:
Button(onClick = { onKirim() }) {
Text("Kirim")
}
OutlinedTextField(
value = pesan,
onValueChange = { pesan = it },
label = { Text("Pesan") },
modifier = Modifier.fillMaxWidth()
)OutlinedTextField adalah input teks standar Material 3 dengan label bawaan. onValueChange mengirim perubahan setiap karakter — pola state yang akan dikupas di episode 5 dan 7.
Card membungkus konten dengan permukaan terangkat, sedangkan Scaffold menyediakan kerangka layar dengan top bar, content, dan floating action button:
Scaffold(
topBar = { TopAppBar(title = { Text("Beranda") }) },
floatingActionButton = {
FloatingActionButton(onClick = { }) {
Text("+")
}
}
) { padding ->
Card(
modifier = Modifier
.fillMaxWidth()
.padding(padding)
.padding(16.dp)
) {
Text("Konten utama", Modifier.padding(16.dp))
}
}Scaffold meneruskan padding lewat lambda content — kalian wajib menerapkan padding ini ke konten agar tidak tertutup top bar. Pola slot API yang kalian lihat di episode 2 ada di sini.
Modifier dirangkai dengan notasi titik. Urutan penting: modifier pertama paling luar. Contoh di bawah mengatur ukuran, lalu padding, lalu background — hasil akhirnya background mengikuti area setelah padding:
Modifier
.fillMaxWidth()
.padding(16.dp)
.background(Color.LightGray)
.clip(RoundedCornerShape(8.dp))clip membatasi bentuk konten berikutnya, jadi urutan setelah background memotong sudut. Modifier seperti .weight di dalam Row atau Column membuat elemen mengisi ruang tersisa — dasar untuk layout responsif.
Ukuran layar Android bervariasi. BoxWithConstraints memberi kalian batas constraint yang tersedia sehingga layout bisa beradaptasi:
@Composable
fun DaftarBerita() {
BoxWithConstraints {
val isLebar = maxWidth > 600.dp
if (isLebar) {
Row {
HeaderBerita(Modifier.weight(1f))
DetailBerita(Modifier.weight(1f))
}
} else {
Column {
HeaderBerita(Modifier.fillMaxWidth())
DetailBerita(Modifier.fillMaxWidth())
}
}
}
}maxWidth > 600.dp mendeteksi layar lebar (tablet atau landscape), lalu beralih dari Column menjadi Row dengan weight. Ini pola sederhana untuk mulai membangun UI adaptif. Untuk mengetahui ukuran layar emulator yang sedang aktif, jalankan adb shell wm size dan adb shell wm density di terminal.
Episode 4 melengkapi kalian dengan building blocks layout: Column, Row, Box untuk penyusunan dasar, LazyColumn dan LazyRow untuk daftar, komponen Material 3 seperti Button, TextField, Card, dan Scaffold, sistem Modifier untuk kontrol visual, serta BoxWithConstraints untuk layout responsif.
Inti yang harus dibawa pulang:
weight di dalam Row dan Column membuat elemen mengisi ruang.Di episode 5 selanjutnya kita akan membahas state dan recomposition — state hoisting, remember, mutableStateOf, integrasi ViewModel, snapshotFlow dan derivedStateOf, serta strategi mengelola state agar UI selalu sinkron dengan data.