Sebelum Jetpack Compose muncul pada 2021, semua UI Android ditulis dengan XML. Hingga kini, banyak codebase masih memakai XML dan library pihak ketiga tetap mendukungnya. Memahami LinearLayout, ConstraintLayout, dan komponen umum seperti TextView, Button, dan RecyclerView tetap relevan baik untuk membaca kode lama maupun bekerja sama dengan tim yang belum migrasi ke Compose. Bab ini memetakan konsep kunci layout XML dan menunjukkan bagaimana setiap layout manager menyusun children-nya.
LinearLayout dan ConstraintLayout #
LinearLayout menyusun children dalam satu arah: horizontal atau vertical. Setiap child diberi posisi berurutan sesuai urutan deklarasi dan atribut layout_weight jika perlu. Layout ini sederhana namun tidak efisien bila hirarki bersarang dalam — setiap level LinearLayout menambah pass pengukuran.
ConstraintLayout adalah penerus yang direkomendasikan untuk layout kompleks. Layout ini bebas menempatkan view dengan constraint (garis penghubung) antar view, mirip Auto Layout di iOS atau ConstraintSolver. Keunggulan utamanya: hirarki tetap rata sehingga pass pengukuran lebih cepat.
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/judul"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Daftar Tugas"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/tambah"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tambah"
app:layout_constraintTop_toBottomOf="@id/judul"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>Common Views #
Komponen yang paling sering dijumpai di hampir setiap aplikasi Android:
| Komponen | Fungsi |
|---|---|
| TextView | Menampilkan teks statis |
| EditText | Input teks dari pengguna |
| Button | Tombol untuk memicu aksi |
| ImageView | Menampilkan gambar |
| RecyclerView | Daftar panjang dengan recyclable ViewHolder |
| ScrollView | Wadah yang dapat di-scroll vertikal |
RecyclerView adalah komponen paling kompleks di antara yang lain. Komponen ini tidak menampilkan data secara langsung, melainkan mendelegasikan ke Adapter yang membuat ViewHolder untuk setiap tipe baris. ViewHolder yang sudah terlihat di-recycle saat pengguna menggulir, sehingga daftar 10.000 item tetap mulus karena hanya sedikit ViewHolder yang aktif di memori.
Simulasi Layout Manager sebagai Data #
Cuplikan berikut memodelkan LinearLayout, ConstraintLayout, dan RecyclerView sebagai sealed class Layout. Method measure mengembalikan posisi setiap child seperti yang dilakukan layout manager sungguhan:
// layouts_ui_components.kt
// Mensimulasikan tiga layout klasik Android (LinearLayout, ConstraintLayout,
// RecyclerView) sebagai model data ringkas. Menghitung posisi dan urutan
// children meniru cara layout manager menyusun view.
sealed class Layout {
abstract fun measure(children: List<String>): List<Pair<String, Int>>
}
class LinearLayout(val orientation: String) : Layout() {
override fun measure(children: List<String>): List<Pair<String, Int>> {
val pos = if (orientation == "horizontal") 0 else 0
return children.mapIndexed { i, name -> name to (pos + i * 50) }
}
}
class ConstraintLayout : Layout() {
override fun measure(children: List<String>): List<Pair<String, Int>> {
// ConstraintLayout bebas menempatkan view di koordinat (x,y) 2D
return children.mapIndexed { i, name -> name to (i * 80) }
}
}
class RecyclerView(val adapter: ListAdapter) : Layout() {
override fun measure(children: List<String>): List<Pair<String, Int>> =
adapter.bind().mapIndexed { i, name -> name to (i * 72) }
}
class ListAdapter(private val data: List<String>) {
fun bind(): List<String> = data.map { "ViewHolder($it)" }
}
fun main() {
val items = listOf("Budi", "Siti", "Andi", "Dewi")
val vertical = LinearLayout("vertical")
println("LinearLayout vertical:")
vertical.measure(items).forEach { (name, pos) -> println(" $name y=$pos") }
val horizontal = LinearLayout("horizontal")
println("LinearLayout horizontal:")
horizontal.measure(items).forEach { (name, pos) -> println(" $name x=$pos") }
val constraint = ConstraintLayout()
println("ConstraintLayout:")
constraint.measure(items).forEach { (name, pos) -> println(" $name pos=$pos") }
val rv = RecyclerView(ListAdapter(items))
println("RecyclerView (rebind adapter):")
rv.measure(items).forEach { (vh, pos) -> println(" $vh y=$pos") }
}Output yang Dihasilkan:
LinearLayout vertical:
Budi y=0
Siti y=50
Andi y=100
Dewi y=150
LinearLayout horizontal:
Budi x=0
Siti x=50
Andi x=100
Dewi x=150
ConstraintLayout:
Budi pos=0
Siti pos=80
Andi pos=160
Dewi pos=240
RecyclerView (rebind adapter):
ViewHolder(Budi) y=0
ViewHolder(Siti) y=72
ViewHolder(Andi) y=144
ViewHolder(Dewi) y=216Perhatikan bahwa LinearLayout vertikal menempatkan children pada koordinat y berbeda, ConstraintLayout menempatkannya bebas, dan RecyclerView memanggil adapter.bind() untuk membuat ViewHolder per item. Pola pemisahan layout manager dari data inilah yang membuat RecyclerView fleksibel — kita bisa mengganti LayoutManager tanpa menyentuh adapter.
Material Design #
Material Design adalah sistem desain resmi Google yang menyediakan komponen siap pakai: MaterialButton, TextInputLayout, BottomNavigationView, FloatingActionButton, dan Snackbar. Library com.google.android.material:material harus ditambahkan di build.gradle.kts. Komponen Material mengikuti pedoman elevasi, gerak, dan tipografi yang konsisten lintas platform Google, sehingga aplikasi terasa native tanpa perlu desainer khusus.
Referensi Lanjutan #
- Jetpack Compose — rujukan Jetpack Compose sebagai toolkit UI deklaratif modern pengganti layout berbasis XML
Selanjutnya #
Layout XML memberi pondasi pemahaman, tetapi masa depan UI Android adalah deklaratif. Chapter Jetpack Compose Fundamentals akan memperkenalkan @Composable, Column, Row, Box, dan konsep recomposition.