Jetpack Compose adalah toolkit UI modern untuk Android yang menggantikan XML dengan fungsi Kotlin beranotasi @Composable. Alih-alih mendeskripsikan apa yang harus dilakukan untuk membangun UI (imperatif seperti findViewById, setText, addView), kita mendeskripsikan apa yang ingin ditampilkan (deklaratif). Compose runtime yang menjaga sinkronisasi antara state dan tampilan. Pada bab ini kita memperkenalkan elemen dasar Compose: Column, Row, Box, Text, Button, dan @Preview.
Apa itu Fungsi Composable #
Fungsi composable adalah fungsi Kotlin biasa dengan anotasi @Composable. Fungsi ini menerima data, mengembalikan deskripsi UI, dan tidak memiliki side effect. Compose runtime memanggil fungsi tersebut setiap kali state berubah, lalu membandingkan hasil dengan pohon UI sebelumnya untuk menentukan apa yang perlu di-render ulang.
@Composable
fun Salam(nama: String) {
Text(text = "Halo, $nama!")
}Tidak ada kelas View, tidak ada LayoutInflater, tidak ada XML. Seluruh UI hanyalah panggilan fungsi Kotlin. Sifat deklaratif ini membuat kode UI lebih pendek, lebih mudah diuji, dan lebih ramah terhadap refactoring.
Column, Row, dan Box #
Compose menyediakan tiga layout utama untuk menyusun composable:
| Layout | Sumbu utama | Kegunaan |
|---|---|---|
Column | Vertikal | Daftar vertikal (form, daftar pendek) |
Row | Horizontal | Tombol sejajar, chip filter |
Box | Tumpang tindih | Overlay, badge di atas gambar |
Setiap layout menerima Modifier untuk mengatur padding, ukuran, dan lain-lain. Modifier dirantai dengan titik (chain) sehingga urutan menentukan hasil: Modifier.padding(8.dp).fillMaxWidth() berbeda dengan Modifier.fillMaxWidth().padding(8.dp).
Text dan Button #
Text dan Button adalah composable paling dasar. Text menerima string dan opsional style (tipografi Material), sedangkan Button menerima lambda onClick dan konten composable di dalamnya.
@Composable
fun TombolTambah(onClick: () -> Unit) {
Button(onClick = onClick) {
Text("Tambah")
}
}Saat tombol diklik, lambda onClick dipanggil. Lambda ini biasanya memperbarui state yang kemudian memicu recomposition — materi yang akan dibahas tuntas pada chapter State dan Recomposition.
Preview Function #
Anotasi @Preview menandai fungsi composable yang akan ditampilkan di panel Preview Android Studio tanpa menjalankan aplikasi penuh. Preview sangat berguna untuk iterasi desain cepat karena setiap perubahan kode langsung terlihat. Preview function biasanya diletakkan di file yang sama dengan composable utamanya.
@Preview(showBackground = true)
@Composable
fun PreviewHalamanUtama() {
HalamanUtama()
}Preview dapat menerima parameter showBackground, widthDp, heightDp, dan uiMode untuk mensimulasikan berbagai kondisi peranti. Kita juga dapat membuat beberapa preview function untuk kondisi terang/gelap atau layar besar/kecil.
Simulasi Pohon Composable #
Karena Compose toolkit tidak tersedia di luar Android, cuplikan berikut memodelkan pohon composable sebagai sealed class ComposeNode. Fungsi Text, Button, Column, Row, dan Box mengembalikan node yang kemudian dirender menjadi teks berindentasi:
// jetpack_compose_fundamentals.kt
// Mendemonstrasikan konsep Compose: composable function, Column/Row/Box,
// Text, Button, dan Preview — sebagai fungsi murni yang mengembalikan pohon
// node UI ringkas. Tidak memakai runtime Compose sungguhan.
sealed class ComposeNode {
abstract val tag: String
}
class TextNode(val text: String) : ComposeNode() {
override val tag = "Text"
}
class ButtonNode(val label: String, val onClick: () -> Unit) : ComposeNode() {
override val tag = "Button"
}
class ColumnNode(val children: List<ComposeNode>) : ComposeNode() {
override val tag = "Column"
}
class RowNode(val children: List<ComposeNode>) : ComposeNode() {
override val tag = "Row"
}
class BoxNode(val children: List<ComposeNode>) : ComposeNode() {
override val tag = "Box"
}
// Fungsi "composable" yang mengembalikan node (mensimulasikan @Composable)
fun Text(s: String): ComposeNode = TextNode(s)
fun Button(label: String, onClick: () -> Unit = {}): ComposeNode = ButtonNode(label, onClick)
fun Column(vararg children: ComposeNode): ComposeNode = ColumnNode(children.toList())
fun Row(vararg children: ComposeNode): ComposeNode = RowNode(children.toList())
fun Box(vararg children: ComposeNode): ComposeNode = BoxNode(children.toList())
// Fungsi preview yang merender pohon menjadi teks indentasi
fun renderTree(node: ComposeNode, indent: String = ""): String {
val head = "$indent<${node.tag}>"
val body = when (node) {
is TextNode -> listOf("$indent text=\"${node.text}\"")
is ButtonNode -> listOf("$indent label=\"${node.label}\"")
is ColumnNode -> node.children.flatMap { listOf(renderTree(it, "$indent ")) }
is RowNode -> node.children.flatMap { listOf(renderTree(it, "$indent ")) }
is BoxNode -> node.children.flatMap { listOf(renderTree(it, "$indent ")) }
}
return (listOf(head) + body).joinToString("\n")
}
// Composable utama yang menyusun UI lengkap
fun HalamanUtama(): ComposeNode = Column(
Text("Daftar Tugas"),
Row(
Text("Halo, Budi"),
Button("Tambah") { println("Klik Tambah") }
),
Box(
Text("Item 1"),
Text("Item 2")
)
)
// Fungsi @Preview menampilkan preview UI tanpa menjalankan aplikasi
fun PreviewHalamanUtama(): ComposeNode = HalamanUtama()
fun main() {
val tree = PreviewHalamanUtama()
println(renderTree(tree))
}Output yang Dihasilkan:
<Column>
<Text>
text="Daftar Tugas"
<Row>
<Text>
text="Halo, Budi"
<Button>
label="Tambah"
<Box>
<Text>
text="Item 1"
<Text>
text="Item 2"Output pohon node menunjukkan bagaimana Compose runtime melihat UI: sebagai hirarki node composable, bukan sebagai view dalam XML. Saat state berubah, hanya cabang yang bergunakan yang akan dirender ulang.
Referensi Lanjutan #
- Jetpack Compose — dokumentasi resmi Jetpack Compose untuk fondasi UI deklaratif di Android
Selanjutnya #
Pondasi composable sudah dipasang, namun banyak pertanyaan praktis belum terjawab: kapan fungsi composable akan dipanggil ulang, apa aturan anotasi @Composable, dan bagaimana parameternya memengaruhi recomposition. Kita akan membedahnya pada chapter Composable Functions.