Episode ini membangun komponen sendiri: composable layout kustom dengan MeasurePolicy, modifier lanjutan dan pointer input, primitif UI yang reusable, serta pengembangan komponen kompleks dari nol.

Column, Row, dan Box menutupi sebagian besar kebutuhan, tapi kadang kalian butuh tata letak yang tidak ada di library: flow text, staggered grid, atau batang yang mengisi ruang dengan aturan sendiri. Di situlah custom layout masuk.
Episode 18 membuka lapisan bawah Compose: API Layout untuk mengukur dan menempatkan, Modifier.layout dan Modifier.drawBehind untuk efek, serta pointer input untuk interaksi. Dengan ini kalian bisa membangun primitif UI yang reusable dan komponen kompleks.
Episode 18 ini meliputi layout kustom, modifier lanjutan, pointer input, dan pengembangan komponen.
Composable Layout menerima content dan MeasurePolicy yang bertanggung jawab mengukur dan menempatkan anak:
@Composable
fun FlowRow(
modifier: Modifier = Modifier,
content: @Composable () -> Unit
) {
Layout(
modifier = modifier,
content = content
) { measurables, constraints ->
var x = 0
var y = 0
var maxBaris = 0
val placeables = measurables.map { measurable ->
val placeable = measurable.measure(constraints.copy(minWidth = 0))
if (x + placeable.width > constraints.maxWidth) {
x = 0
y += maxBaris
maxBaris = 0
}
val hasil = PlaceablePos(x, y, placeable)
maxBaris = maxOf(maxBaris, placeable.height)
x += placeable.width
hasil
}
layout(
width = constraints.maxWidth,
height = y + maxBaris
) {
placeables.forEach { pos ->
pos.placeable.placeRelative(pos.x, pos.y)
}
}
}
}measurable.measure(constraints) mengukur tiap anak, lalu layout(width, height) menetapkan ukuran keseluruhan dan placeRelative(x, y) menempatkan anak. Pola ini adalah mesin di balik banyak library layout. Untuk mengamati hasil layout kustom di perangkat, bangun dan pasang aplikasi dengan ./gradlew :app:installDebug.
Gunakan custom layout saat perilaku tidak bisa diungkapkan dengan composable bawaan: text wrapping khusus, distribusi bobot tak biasa, atau tata letak yang membaca data terlebih dahulu. Jika Column dan Row sudah cukup, jangan paksakan.
Modifier kustom bisa mengubah ukuran dan posisi elemen yang dimodifikasi:
Modifier.layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
layout(placeable.width, placeable.height) {
placeable.placeRelative(placeable.width / 2, 0)
}
}Modifier.layout memindahkan elemen setengah lebar ke kanan. Modifier ini memberi kontrol halus per elemen — kebalikan dari Layout yang mengatur banyak anak.
Untuk efek visual, drawBehind menggambar di belakang konten, dan clickable atau pointerInput menangani interaksi:
Modifier
.drawBehind {
drawCircle(
color = HijauMuda,
radius = 8.dp.toPx()
)
}
.pointerInput(Unit) {
detectTapGestures { posisi ->
onTitikDiklik(posisi)
}
}drawCircle menggambar lingkaran di belakang konten, dan detectTapGestures meneruskan koordinat tap. Kombinasi draw dan pointer adalah fondasi grafik interaktif.
Gabungkan primitif di atas menjadi komponen utuh — misalnya kartu yang bisa diseret dengan indikator status:
@Composable
fun KartuDrag(
onSeret: (Float) -> Unit,
modifier: Modifier = Modifier
) {
var offsetY by remember { mutableFloatStateOf(0f) }
Card(
modifier = modifier
.offset { IntOffset(0, offsetY.roundToInt()) }
.pointerInput(Unit) {
detectDragGestures { change, _ ->
change.consume()
offsetY += change.positionChange().y
onSeret(offsetY)
}
}
) {
Text("Seret saya", Modifier.padding(16.dp))
}
}offsetY menyimpan posisi drag, detectDragGestures memperbaruinya, dan offset menerapkannya. change.consume() menandakan gesture ditangani. Komponen seperti ini bisa dipakai ulang di seluruh aplikasi.
Bungkus komponen kustom menjadi primitif design system: Badge, RatingBar, TabStrip kustom. Dengan menerima Modifier sebagai parameter, setiap primitif tetap bisa dikomposisi dan di-test seperti komponen lain.
Episode 18 membuka lapisan bawah Compose: composable Layout dengan MeasurePolicy untuk tata letak kustom, Modifier.layout dan drawBehind untuk kontrol per elemen, pointer input untuk interaksi, serta pembangunan komponen kompleks dan primitif design system yang reusable.
Inti yang harus dibawa pulang:
Layout memberi kontrol pengukuran dan penempatan anak.Di episode 19 selanjutnya kita akan membahas operational readiness dan runbooks — penanganan crash dan regresi, pemantauan kesehatan aplikasi dan UI, proses rilis dan strategi rollout, serta menjaga kualitas design yang konsisten.