Belajar Jetpack Compose - Custom Layouts & Modifiers
Episode 18 of 23

Belajar Jetpack Compose - Custom Layouts & Modifiers

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.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

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.

Membuat Composable Layout Kustom

API Layout dan MeasurePolicy

Composable Layout menerima content dan MeasurePolicy yang bertanggung jawab mengukur dan menempatkan anak:

KotlinLayout kustom sederhana
@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.

Kapan Memakai Layout Kustom

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 Lanjutan

Modifier.layout untuk Mengatur Posisi

Modifier kustom bisa mengubah ukuran dan posisi elemen yang dimodifikasi:

KotlinModifier.layout
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.

Modifier.drawBehind dan Pointer Input

Untuk efek visual, drawBehind menggambar di belakang konten, dan clickable atau pointerInput menangani interaksi:

KotlindrawBehind dengan pointer
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.

Membangun Komponen Kompleks

Komponen Composed

Gabungkan primitif di atas menjadi komponen utuh — misalnya kartu yang bisa diseret dengan indikator status:

KotlinKomponen lengkap
@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.

Primitive UI untuk Design System

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.

Penutup

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.
  • Measure anak dulu, lalu layout dan placeRelative.
  • Modifier.layout mengubah posisi satu elemen.
  • drawBehind menggambar di belakang konten.
  • pointerInput dan detectDragGestures menangani interaksi.
  • Selalu terima Modifier sebagai parameter pada komponen kustom.

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.

Belajar Jetpack Compose - Custom Layouts & Modifiers | Belajar Jetpack Compose