Modifier — adalah objek yang tidak dapat diubah di Jetpack Compose yang menentukan properti komponen UI: ukuran, margin, latar belakang, pemrosesan gestur, dan perilaku. Pengubah digabungkan dalam rantai melalui pemanggilan berurutan, di mana urutan penerapannya secara kritis memengaruhi hasil. Menurut Google Android Developers, 2026, penggunaan Modifier yang benar adalah dasar membangun antarmuka yang fleksibel dan berperforma tinggi di UI deklaratif.
Poin Utama
Modifier — adalah antarmuka dari paket androidx.compose.ui yang mengimplementasikan pola Composite. Setiap pengubah adalah elemen rantai yang membungkus yang sebelumnya dan menambahkan perilakunya sendiri. Modifier bersifat tidak berubah — setiap perubahan menciptakan objek baru melalui penyalinan dengan penambahan elemen baru ke rantai. Ini memungkinkan berbagi satu Modifier secara aman di antara banyak komponen.
Fungsi-fungsi pengubah dasar dipanggil melalui objek pendamping Modifier (misalnya, Modifier.padding(), Modifier.fillMaxWidth()). Setiap fungsi mengembalikan Modifier baru dengan elemen yang ditambahkan. Jika ada beberapa pengubah, mereka digabungkan dalam rantai: Modifier.padding(16.dp).fillMaxWidth().background(Color.Blue). Urutan adalah arah dari luar ke dalam relatif terhadap elemen UI.
Tidak seperti View tradisional, di mana properti diatur melalui setter (view.setPadding(...), view.setBackground(...)), di Compose Modifier adalah deskripsi deklaratif. Komponen tidak "menerapkan" pengubah selama eksekusi — LayoutNode pada fase komposisi melintasi rantai Modifier dan mengumpulkan daftar Modifier.Element, yang kemudian diproses pada fase pengukuran dan penataan.
Urutan pengubah — salah satu kesalahan paling umum di Compose. Setiap pengubah membungkus yang sebelumnya, dan operasi dijalankan dari luar ke dalam. Misalnya, padding(16.dp).clickable { }: pertama margin ditambahkan di sekitar elemen, kemudian area klik mencakup juga margin. clickable { }.padding(16.dp): pertama area klik sama dengan ukuran elemen, kemudian margin ditambahkan di sekelilingnya — klik pada margin tidak akan berfungsi.
Aturan mengingat: baca rantai dari kiri ke kanan dan terapkan dari luar ke dalam. Pengubah pertama — yang paling luar, diterapkan pada area di sekitar elemen. Pengubah terakhir — yang paling dalam, diterapkan langsung ke konten. Pengubah ukuran (size, fillMaxWidth) harus mengikuti margin, jika margin diperlukan dari induk, atau sebelum margin, jika konten harus dibatasi terlebih dahulu, kemudian dipusatkan.
Contoh: size(100.dp).padding(10.dp) — elemen ukuran tetap 100dp, kemudian padding 10dp di luar (ukuran akhir 120dp). padding(10.dp).size(100.dp) — padding 10dp mengurangi ruang yang tersedia menjadi (induk - 20dp), kemudian size(100dp) dapat melampaui induk. Selalu pikirkan urutan secara sadar, menggunakan tes tampilan untuk memverifikasi hasil.
| Urutan | Hasil |
|---|---|
| padding → clickable | Klik berfungsi juga di area margin |
| clickable → padding | Klik hanya berfungsi pada konten, margin adalah zona mati |
| size → padding | Elemen size(100), padding di luar → 100+2*pad |
| padding → size | padding mengurangi ruang, size dapat melampaui batas |
| background → padding | Latar belakang mengisi seluruh elemen termasuk area luar |
| padding → background | Latar belakang hanya di dalam margin (area luar transparan) |
Pustaka standar Compose mencakup ~50+ pengubah, dibagi ke dalam kategori. Ukuran dan posisi: Modifier.size(), width(), height(), fillMaxSize(), fillMaxWidth(), fillMaxHeight(), defaultMinSize(), requiredSize(). Margin dan batas: padding(), offset(), margin (ditempatkan melalui padding induk atau Layout). Dekorasi: background(), border(), clip(), alpha(), shadow(), blur().
Perilaku dan gestur: clickable(), combinedClickable(), pointerInput(), draggable(), swipeable(). Penataan dalam wadah: weight() (untuk Row/Column), align(), alignBy(), matchParentSize(). Semantik dan aksesibilitas: semantics(), testTag(), clearAndSetSemantics(). Menggambar: drawBehind(), drawWithContent(), drawModifier() — pengubah yang memungkinkan penggambaran kustom di kanvas.
Pengubah semantik — kategori khusus. Modifier.semantics {} menentukan bagaimana elemen akan direpresentasikan di pohon Accessibility. Compose secara otomatis mengisi semantik dari teks, tetapi untuk komponen kustom, peran, status, dan tindakan harus ditentukan secara manual. Ini sangat penting untuk kepatuhan WCAG 2.2 dan fungsi TalkBack (Android) serta VoiceOver (iOS) yang benar.
@Composable
fun ModifierDemo() {
// Rantai pengubah dengan urutan yang benar
Box(
modifier = Modifier
.size(150.dp)
.padding(8.dp)
.border(2.dp, Color.Gray)
.background(Color(0xFFE3F2FD))
.clickable { /* handle click */ }
.semantics {
contentDescription = "Demo card with click action"
role = Role.Button
}
) {
Text("Sentuh saya")
}
}
Modifier.composed — adalah metode pabrik yang memungkinkan pembuatan pengubah komposit yang dapat menggunakan pengubah lain, LocalComposition, dan status lokal. Tidak seperti fungsi ekstensi biasa, composed membuat instance setiap kali diterapkan, yang memungkinkan memiliki status sendiri di dalam pengubah.
Kapan menggunakan composed: kombinasi berulang pengubah (misalnya, gaya kartu standar: padding + background + border + clickable); pengubah dengan status (perubahan latar belakang animasi saat ditekan); akses ke CompositionLocals (skema warna MaterialTheme, kerapatan piksel). Dalam kasus biasa, fungsi ekstensi biasa tanpa composed sudah cukup.
Performa composed: setiap pemanggilan membuat objek pengubah baru, yang dapat menyebabkan alokasi berlebihan saat rekomposisi. Untuk mencegahnya, bungkus composed dalam remember. Google merekomendasikan penggunaan composed hanya ketika benar-benar membutuhkan status atau CompositionLocal di dalamnya. Untuk kombinasi statis, gunakan fungsi ekstensi biasa.
// Pengubah kustom melalui composed dengan status
fun Modifier.cardStyle(
elevation: Dp = 4.dp,
isSelected: Boolean = false
): Modifier = this.composed {
val backgroundColor = if (isSelected)
MaterialTheme.colorScheme.primaryContainer
else
MaterialTheme.colorScheme.surface
this
.fillMaxWidth()
.padding(12.dp)
.background(backgroundColor, RoundedCornerShape(8.dp))
.shadow(elevation, RoundedCornerShape(8.dp))
}
// Contoh penggunaan
@Composable
fun CardList() {
Column {
Box(Modifier.cardStyle()) { Text("Item 1") }
Box(Modifier.cardStyle(isSelected = true)) { Text("Dipilih") }
}
}
// Versi statis (tanpa composed) — lebih cepat
fun Modifier.simpleCardStyle(): Modifier =
this.fillMaxWidth().padding(8.dp).clip(RoundedCornerShape(4.dp))
Hindari pembuatan ulang Modifier pada setiap rekomposisi. Jika pengubah tidak bergantung pada data yang berubah — tempatkan dalam konstanta atau remember. Setiap kali Modifier.padding().background() dipanggil, objek Modifier.Element baru dibuat. Dalam komponen terisolasi, ini tidak terlihat, tetapi di LazyColumn dengan ratusan elemen, alokasi berlebihan menyebabkan kelambatan yang terlihat saat menggulir.
Aturan: jika rantai pengubah tidak bergantung pada parameter fungsi Composable — deklarasikan sebagai val di luar fungsi (di tingkat file atau Companion). Jika bergantung — gunakan remember(ketergantungan) { ... }. Untuk pengubah yang selalu sama, cara paling efisien adalah val di luar Composable: objek semacam itu dibuat sekali untuk seluruh masa pakai aplikasi.
Praktik terbaik pengurutan Modifier: tempatkan pengubah dalam urutan logis: pertama ukuran/margin (layout), kemudian dekorasi (background, border), lalu perilaku (clickable, pointerInput). Ini tidak hanya meningkatkan keterbacaan, tetapi juga membantu Compose Runtime mengoptimalkan rantai pada fase pengukuran. Juga hindari Box bersarang berlebihan dengan Modifier berbeda — seringkali satu Modifier pada wadah induk dapat menggantikan 2-3 kotak bersarang.
// ✅ Baik: konstanta di luar Composable
private val cardModifier = Modifier
.fillMaxWidth()
.padding(16.dp)
.clip(RoundedCornerShape(8.dp))
@Composable
fun CardContent() {
Box(cardModifier.background(Color.White)) { ... }
}
// ❌ Buruk: pembuatan ulang pada setiap rekomposisi
@Composable
fun BadCard() {
Box(Modifier.fillMaxWidth().padding(16.dp)) { ... }
}
// ✅ Baik: remember untuk Modifier dinamis
@Composable
fun DynamicCard(color: Color) {
val modifier = remember(color) {
Modifier.fillMaxWidth().background(color)
}
Box(modifier) { ... }
}
Pertanyaan yang Sering Diajukan
Ya, Modifier tidak dapat diubah, jadi satu objek dapat digunakan dengan aman di beberapa tempat. Namun, jika Anda menggunakan composed-modifier, setiap pemanggilan membuat instance baru. Untuk rantai statis, konstanta atau val di luar Composable adalah solusi optimal.
Gunakan Layout Inspector di Android Studio — ia secara visual menunjukkan batas setiap Modifier. Untuk debugging terprogram, tambahkan Modifier.border() dengan warna berbeda di setiap langkah rantai untuk melihat batas penerapan setiap pengubah.
Modifier.then(other) menggabungkan rantai other ke this. Pemanggilan berurutan (Modifier.a().b()) setara dengan Modifier.then(a()).then(b()). Tidak ada perbedaan — ini adalah mekanisme rantai yang sama. then() berguna ketika Anda perlu menggabungkan rantai yang sudah jadi dari sebuah variabel.
Modifier.semantics {} menentukan bagaimana elemen akan dideskripsikan untuk pembaca layar. Modifier.clickable() secara otomatis menambahkan peran Button dan Action(OnClick). Untuk gestur kustom, Anda harus menentukan semantics secara eksplisit. Tanpa pengubah semantik, pengguna TalkBack tidak akan dapat berinteraksi dengan komponen kustom.
Modifier.background(color, shape) berfungsi dengan sudut, tetapi clip() harus SEBELUM background agar sudut terpotong. Urutan yang benar: clip(shape).background(color). Jika Anda perlu memotong juga konten di dalamnya, gunakan clipToBounds() pada induk.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga