Kami menjelaskan apa itu ConstraintLayout — sistem penentuan posisi fleksibel untuk Android yang memungkinkan pembuatan hierarki datar view menggunakan constraint (batasan) sebagai pengganti LinearLayout dan RelativeLayout bersarang. ConstraintLayout memecahkan masalah "sarang setan" (layout nesting hell), mengurangi kedalaman hierarki menjadi satu tingkat dan mempercepat rendering layar. Pustaka ini bagian dari Jetpack dan tersedia mulai Android 2.3 (API 9) melalui support-library. Mekanisme dasar dijelaskan di dokumentasi resmi Android.
Poin Utama
ConstraintLayout — adalah ViewGroup dari pustaka AndroidX ConstraintLayout, dirancang untuk membuat antarmuka yang fleksibel dan berkinerja tinggi melalui batasan deklaratif (constraints). Tidak seperti LinearLayout yang menyusun elemen dalam satu baris, atau RelativeLayout yang memposisikan relatif terhadap tetangga, ConstraintLayout memungkinkan Anda mengikat setiap elemen relatif terhadap elemen lain dan induk secara bersamaan.
Pustaka ini diumumkan di Google I/O 2016 sebagai solusi untuk mempercepat rendering layar yang kompleks. Masalah utama yang dipecahkan ConstraintLayout adalah sarang tata letak. Setiap ViewGroup bersarang menambahkan setidaknya dua lintasan measure dan satu lintasan layout. Layar dengan 4 tingkat sarang menjalankan 8 lintasan measure; ConstraintLayout dengan fungsionalitas yang sama — hanya 2 lintasan. Menurut data Google (Android Performance Blog, 2017), mengganti tiga LinearLayout bersarang dengan satu ConstraintLayout mengurangi waktu onMeasure sebesar 40%.
Versi saat ini ConstraintLayout 2.1.4 bekerja secara stabil pada Android 2.3+ (API 9) melalui AndroidX. Di versi 2.0, muncul penentuan posisi melingkar, Flow (pemindahan otomatis elemen) dan dukungan MotionLayout. ConstraintLayout wajib dipahami untuk pengembangan Android modern — digunakan di Jetpack Compose sebagai konsep dasar pengubah, di template default Android Studio, dan di Material Design 3.
Hierarki datar ConstraintLayout berarti semua View anak berada pada tingkat sarang yang sama. Alih-alih menempatkan elemen A di LinearLayout, dan LinearLayout di RelativeLayout, semua elemen diikat langsung ke ConstraintLayout induk atau satu sama lain melalui atribut. Ini menghasilkan: konsumsi memori lebih rendah (setiap ViewGroup adalah objek di Java heap), percepatan lintasan layout (lebih sedikit panggilan rekursif), perilaku lebih dapat diprediksi saat perubahan ukuran layar.
Constraint — adalah hubungan antara tepi satu View (atau pusatnya) dan tepi View lain atau induk. Setiap View dapat memiliki hingga 8 constraint: kiri, atas, kanan, bawah, start, end, baseline, dan tengah. Minimal untuk penentuan posisi, dua constraint tegak lurus sudah cukup (misalnya, atas + kiri).
Format atribut: app:layout_constraint[Sumber]_to[Target]Of="[id]" — di mana Sumber adalah tepi yang diikat (Left, Right, Top, Bottom, Start, End, Baseline), Target adalah tepi sasaran. Contoh: app:layout_constraintTop_toBottomOf="@+id/header" berarti "batas atas elemen saat ini diikat ke batas bawah elemen header". Untuk pengikatan ke induk, id parent digunakan.
Bias (pergeseran) — parameter yang bekerja dengan adanya constraint yang berlawanan (left + right atau top + bottom). Nilai dari 0 hingga 1: 0 — menempel ke tepi kiri/atas, 0.5 — di tengah, 1 — ke tepi kanan/bawah. Atribut: layout_constraintHorizontal_bias (0.0–1.0) dan layout_constraintVertical_bias. Margin diatur dengan android:layout_margin* standar, tetapi constraint dan margin bekerja secara independen: margin adalah jarak dari constraint, bukan dari View tetangga.
Sejak ConstraintLayout 1.1+, dukungan untuk ukuran persentase tersedia melalui layout_constraintWidth_percent dan layout_constraintHeight_percent. Nilai 0.3 berarti 30% dari lebar/tinggi induk. Dalam kombinasi dengan bias, ini memungkinkan pembuatan tata letak adaptif tanpa pemrograman.
Chain (rantai) — adalah grup dari dua atau lebih View yang terhubung dengan constraint dua arah (A terikat ke B, B ke A). Rantai secara otomatis mendistribusikan ruang antar elemen dalam salah satu mode: spread (merata, dengan mempertimbangkan margin), spread_inside (merata, elemen tepi tanpa jarak dari tepi), packed (elemen saling menempel dengan bias bersama). Mode diatur dengan atribut app:layout_constraintHorizontal_chainStyle atau layout_constraintVertical_chainStyle.
Guideline (pedoman) — View pembantu, tidak terlihat saat runtime, tetapi menentukan garis untuk pengikatan. Guideline bisa horizontal atau vertikal, diposisikan dalam dp, persen (app:layout_constraintGuide_percent) atau dengan jarak dari tepi (app:layout_constraintGuide_begin/end). Guidelines sangat penting untuk tata letak adaptif — misalnya, untuk membagi layar menjadi dua bagian yang sama terlepas dari ukuran perangkat.
Menurut data Google I/O 2017, rantai dengan spread_inside 15–20% lebih efisien daripada LinearLayout bersarang dengan weight, karena menghindari lintasan measure ganda yang diperlukan untuk menghitung weight.
Barrier (penghalang) — View virtual yang secara dinamis menyesuaikan posisinya dengan ukuran grup elemen. Tidak seperti Guideline dengan posisi tetap, Barrier "didorong" oleh elemen terlebar dalam grup. Misalnya, jika Anda memiliki judul dan deskripsi dengan panjang yang tidak diketahui, Barrier yang terikat ke tepi kanan teks terlebar memungkinkan Anda menempatkan ikon tepat di sebelahnya. Atribut: app:barrierDirection (left, right, top, bottom, start, end) dan app:constraint_referenced_ids (daftar id yang dipisahkan koma).
Group — kontainer virtual yang mengelola visibilitas beberapa View secara bersamaan. Alih-alih memanggil setVisibility untuk setiap elemen secara terpisah, cukup mengubah visibilitas satu Group. Group tidak memengaruhi penentuan posisi — hanya visibilitas. Flow — pembantu virtual untuk membuat tata letak "mengalir": elemen secara otomatis berpindah ke baris/kolom baru saat ruang tidak mencukupi, seperti teks dalam paragraf. Flow mendukung wrapMode: none, chain, dan aligned.
Alat-alat ini (Barrier, Group, Flow, Guideline) disebut pembantu virtual karena bukan View dalam arti klasik — mereka tidak menempati ruang dalam hierarki dan tidak berpartisipasi dalam fokus atau peristiwa sentuh. Tujuan mereka adalah menyederhanakan pemeliharaan tata letak yang kompleks tanpa menambahkan kontainer bersarang.
Formulir login sederhana dengan kolom email, kata sandi, dan tombol. Semua elemen terikat ke parent, kecuali tombol — berada di bawah kolom kata sandi. Menggunakan hierarki datar — ketiga elemen di tingkat yang sama.
<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">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/email_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="32dp"
android:layout_marginHorizontal="16dp" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/email_input"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"
android:layout_marginHorizontal="16dp" />
<Button
android:id="@+id/login_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/password_input"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="24dp"
android:layout_marginHorizontal="16dp"
android:text="Masuk" />
</androidx.constraintlayout.widget.ConstraintLayout>
Semua elemen memiliki lebar 0dp (match_constraint), yaitu meregang dari start ke end constraint dengan mempertimbangkan margin horizontal. Ini setara dengan match_parent dengan jarak, tetapi tanpa sarang.
Tiga tombol, didistribusikan secara merata secara horizontal dengan jarak dari tepi. Rantai spread_inside menempatkan tombol tepi di tepi dan tombol tengah di tengah di antaranya.
<Button
android:id="@+id/btn_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_center"
android:text="Kiri" />
<Button
android:id="@+id/btn_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn_left"
app:layout_constraintRight_toLeftOf="@+id/btn_right"
android:text="Tengah" />
<Button
android:id="@+id/btn_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn_center"
app:layout_constraintRight_toRightOf="parent"
android:text="Kanan" />
Rantai dibuat secara otomatis ketika elemen memiliki constraint dua arah. Mode spread_inside diatur pada elemen rantai mana pun melalui app:layout_constraintHorizontal_chainStyle="spread_inside". Ini menghilangkan kebutuhan menggunakan LinearLayout dengan weightSum dan layout_weight.
Membuat dua kolom yang sama melalui Guideline vertikal pada 50%. Elemen kiri terikat ke tepi kiri parent dan dengan tepi kanan ke guideline; elemen kanan — dengan tepi kiri ke guideline dan ke tepi kanan parent.
<androidx.constraintlayout.widget.Guideline
android:id="@+id/gl_midpoint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<TextView
android:id="@+id/left_card"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/gl_midpoint"
android:layout_margin="8dp"
android:background="@color/card_background" />
<TextView
android:id="@+id/right_card"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/gl_midpoint"
app:layout_constraintRight_toRightOf="parent"
android:layout_margin="8dp"
android:background="@color/card_background" />
Guideline dengan persentase 0.5 secara otomatis menyesuaikan dengan lebar layar. Di tablet dan ponsel, rasio kolom tetap 50/50. Untuk nomenklatur kiri/kanan, gunakan atribut start/end untuk kompatibilitas RTL.
Tabel perbandingan tiga ViewGroup utama untuk pengembangan Android: ConstraintLayout, LinearLayout, dan RelativeLayout. Kriteria: fleksibilitas, kinerja, kompleksitas kode, dan area aplikasi.
| Karakteristik | ConstraintLayout | LinearLayout | RelativeLayout |
|---|---|---|---|
| Sarang | Datar (satu tingkat) | Memerlukan sarang untuk tata letak kompleks | Satu tingkat, tetapi fleksibilitas terbatas |
| Kinerja measure | 2 lintasan (~40% lebih cepat) | 4+ lintasan dengan weight | 2 lintasan |
| Ukuran persentase | Ya (guide_percent, width_percent) | Hanya melalui weight/frame | Tidak |
| Dukungan RTL | Terintegrasi (start/end) | Terintegrasi | Melalui start/end (API 17+) |
| Barrier/Group/Flow | Ya (pembantu virtual) | Tidak | Tidak |
| Animasi MotionLayout | Ya | Tidak | Tidak |
| Kapan digunakan | Semua tata letak kompleks, layar dengan >5 elemen | Daftar satu arah sederhana, baris dengan tombol | Tata letak relatif sederhana (dari kode lama) |
Menurut Android Vitals (Google, 2025), aplikasi yang menggunakan ConstraintLayout sebagai kontainer utama rata-rata menunjukkan 18% lebih sedikit frame jank saat merender layar kompleks dibandingkan aplikasi dengan LinearLayout bersarang. Di IT Sectr kami beralih ke ConstraintLayout sebagai standar untuk semua tata letak XML pada tahun 2018 — ini mengurangi kedalaman hierarki rata-rata layar dari 4,2 menjadi 1,8 tingkat dan mempercepat pengembangan formulir baru sebesar 25%.
Pertanyaan yang Sering Diajukan
match_parent di ConstraintLayout bekerja seperti biasa — meregangkan View ke ukuran induk. 0dp (match_constraint) berarti ukuran View dihitung dari constraint: jika constraint kiri dan kanan dengan margin ditetapkan, lebar = parent — marginLeft — marginRight. Perbedaan perilaku: match_parent mengabaikan bias dan dapat melampaui batas saat animasi; match_constraint dengan benar memperhitungkan semua batasan dan direkomendasikan Google sebagai mode utama untuk ConstraintLayout.
Gunakan kombinasi: ukuran persentase (layout_constraintWidth_percent) untuk elemen yang harus menempati bagian layar; Guideline dengan persentase untuk membagi layar menjadi zona; Barrier untuk penentuan posisi relatif terhadap konten dinamis; Flow dengan wrapMode untuk memindahkan kartu ke baris baru. Pendekatan alternatif — menggunakan SlidingPaneLayout bersama dengan ConstraintLayout untuk antarmuka master-detail di tablet.
Jetpack Compose tidak menggunakan ConstraintLayout sebagai ViewGroup, tetapi menyediakan versi Compose dari ConstraintLayout (androidx.constraintlayout:constraintlayout-compose) dengan API yang sama di Kotlin DSL: createRefFor(), constrainAs(), linkTo(), chain(), guideFrom(). Ini berguna untuk tata letak kompleks yang lebih mudah dijelaskan melalui constraint daripada melalui Column/Row. Namun, di Compose disarankan untuk memulai dengan Column/Row/Box dan beralih ke ConstraintLayout hanya ketika penentuan posisi relatif yang kompleks diperlukan.
Di Android Studio, buka Layout Inspector (Tools → Layout Inspector), pilih aplikasi yang berjalan, dan arahkan kursor ke elemen yang bermasalah. Anda akan melihat semua constraint, margin, padding, dan bias dalam tampilan tiga dimensi. Untuk XML, gunakan panel Design di editor tata letak — ini menyoroti konflik constraint dengan warna kuning dan tidak adanya constraint dengan warna merah. Di kode, periksa bahwa setiap View memiliki dua constraint tegak lurus, jika tidak elemen akan berada di (0,0).
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