Bemutatjuk, mi az a ConstraintLayout — egy rugalmas pozícionáló rendszer Androidhoz, amely lehetővé teszi lapos nézethierarchiák építését kényszerek (constraints) segítségével az egymásba ágyazott LinearLayout és RelativeLayout helyett. A ConstraintLayout megoldja az "elrendezési pokoli beágyazás" (layout nesting hell) problémáját, egy szintre csökkentve a hierarchia mélységét és felgyorsítva a képernyő megjelenítését. A könyvtár a Jetpack része, és Android 2.3-tól (API 9) érhető el a support-library-n keresztül. Az alapvető mechanizmusok az Android hivatalos dokumentációjában találhatók.
Főbb pontok
ConstraintLayout — egy ViewGroup az AndroidX ConstraintLayout könyvtárból, amely deklaratív kényszerek (constraints) segítségével rugalmas és hatékony felületek létrehozására szolgál. Ellentétben a LinearLayout-tal, amely egy sorba rendezi az elemeket, vagy a RelativeLayout-tal, amely a szomszédokhoz viszonyítva pozícionál, a ConstraintLayout lehetővé teszi, hogy minden elemet egyszerre bármely más elemhez és a szülőhöz rögzítsen.
A könyvtárat a Google I/O 2016-on jelentették be, mint megoldást a bonyolult képernyők megjelenítésének felgyorsítására. A ConstraintLayout által megoldott kulcsprobléma az elrendezések beágyazása. Minden beágyazott ViewGroup legalább két measure- és egy layout-menettel járul hozzá. Egy 4 beágyazási szinttel rendelkező képernyő 8 measure-menetet hajt végre; a ConstraintLayout ugyanazzal a funkcionalitással — csak 2 menetet. A Google adatai szerint (Android Performance Blog, 2017) három beágyazott LinearLayout egy ConstraintLayout-ra cserélése 40%-kal csökkenti az onMeasure időt.
A jelenlegi ConstraintLayout 2.1.4 verzió stabilan működik Android 2.3+ (API 9) rendszeren az AndroidX-en keresztül. A 2.0 verzióban megjelent a körkörös pozícionálás, a Flow (elemek automatikus átvitele) és a MotionLayout támogatása. A ConstraintLayout elengedhetetlen a modern Android-fejlesztés megértéséhez — használják a Jetpack Compose-ban a módosítók alapkoncepciójaként, az Android Studio alapértelmezett sablonjaiban és a Material Design 3-ban.
A ConstraintLayout lapos hierarchiája azt jelenti, hogy az összes gyermek View ugyanazon a beágyazási szinten található. Ahelyett, hogy az A elemet egy LinearLayout-ba, a LinearLayout-ot pedig egy RelativeLayout-ba helyeznénk, az összes elem közvetlenül a szülő ConstraintLayout-hoz vagy egymáshoz van rögzítve attribútumokon keresztül. Ez a következőket eredményezi: alacsonyabb memóriafogyasztás (minden ViewGroup egy objektum a Java heap-ben), a layout menet felgyorsulása (kevesebb rekurzív hívás), kiszámíthatóbb viselkedés a képernyőméret változásainál.
Kényszer (constraint) — egy kapcsolat egy View éle (vagy közepe) és egy másik View vagy a szülő éle között. Minden View-nak legfeljebb 8 kényszere lehet: bal, felső, jobb, alsó, start, end, baseline és közép. A pozícionáláshoz minimum két merőleges kényszer elegendő (például felső + bal).
Az attribútum formátuma: app:layout_constraint[Forrás]_to[Cél]Of="[id]" — ahol a Forrás a rögzített él (Left, Right, Top, Bottom, Start, End, Baseline), a Cél a cél éle. Példa: app:layout_constraintTop_toBottomOf="@+id/header" azt jelenti, hogy "az aktuális elem felső határa a header elem alsó határához van rögzítve". A szülőhöz rögzítéshez a parent azonosító használatos.
Bias (eltolás) — paraméter, amely ellentétes kényszerek (left + right vagy top + bottom) esetén működik. Érték 0-tól 1-ig: 0 — a bal/felső élhez nyomva, 0.5 — középre igazítva, 1 — a jobb/alsó élhez. Attribútumok: layout_constraintHorizontal_bias (0.0–1.0) és layout_constraintVertical_bias. A margó a szabványos android:layout_margin* attribútumokkal állítható be, de a kényszer és a margó függetlenül működik: a margó a kényszertől való távolság, nem a szomszédos View-tól.
A ConstraintLayout 1.1+-tól kezdve a százalékos méretek támogatottak a layout_constraintWidth_percent és layout_constraintHeight_percent segítségével. A 0.3 érték a szülő szélességének/magasságának 30%-át jelenti. A bias-szal kombinálva ez lehetővé teszi adaptív elrendezések létrehozását programozás nélkül.
Chain (lánc) — két vagy több View csoportja, amelyek kétirányú kényszerekkel kapcsolódnak (A B-hez, B A-hoz). A láncok automatikusan elosztják a teret az elemek között a következő módok egyikében: spread (egyenletesen, a margókat figyelembe véve), spread_inside (egyenletesen, a szélső elemek szél nélkül), packed (az elemek egymáshoz nyomva közös bias-szal). A módot a app:layout_constraintHorizontal_chainStyle vagy layout_constraintVertical_chainStyle attribútum állítja be.
Guideline (vezetővonal) — egy segéd View, amely futásidőben láthatatlan, de egy vonalat határoz meg a rögzítéshez. A Guideline lehet vízszintes vagy függőleges, elhelyezve dp-ben, százalékban (app:layout_constraintGuide_percent) vagy széltől való távolsággal (app:layout_constraintGuide_begin/end). A Guideline-ok nélkülözhetetlenek az adaptív elrendezésekhez — például a képernyő két egyenlő félre osztásához a készülék méretétől függetlenül.
A Google I/O 2017 adatai szerint a spread_inside láncok 15–20%-kal hatékonyabbak, mint a weight-tel rendelkező beágyazott LinearLayout-ok, mivel elkerülik a weight kiszámításához szükséges dupla measure-menetet.
Barrier (korlát) — egy virtuális View, amely dinamikusan igazítja a pozícióját az elemcsoport méretéhez. Ellentétben a rögzített pozíciójú Guideline-nal, a Barrier-t a csoport legszélesebb eleme "tolja". Például, ha van egy ismeretlen hosszúságú címe és leírása, a legszélesebb szöveg jobb széléhez rögzített Barrier lehetővé teszi, hogy egy ikont közvetlenül utánuk helyezzen el. Attribútumok: app:barrierDirection (left, right, top, bottom, start, end) és app:constraint_referenced_ids (vesszővel elválasztott azonosítók listája).
Group — egy virtuális konténer, amely egyszerre több View láthatóságát kezeli. Ahelyett, hogy minden elemhez külön setVisibility-t hívna, elegendő egyetlen Group láthatóságát megváltoztatni. A Group nem befolyásolja a pozícionálást — csak a láthatóságot. Flow — egy virtuális segítő "folyékony" elrendezések létrehozásához: az elemek automatikusan új sorba/oszlopba kerülnek, ha nincs elég hely, mint a szöveg egy bekezdésben. A Flow támogatja a wrapMode: none, chain és aligned módokat.
Ezeket az eszközöket (Barrier, Group, Flow, Guideline) virtuális segítőknek nevezzük, mert nem View-ok a klasszikus értelemben — nem foglalnak helyet a hierarchiában és nem vesznek részt a fókuszban vagy érintési eseményekben. Céljuk a bonyolult elrendezések karbantartásának egyszerűsítése anélkül, hogy beágyazott konténereket adnának hozzá.
Egyszerű bejelentkezési űrlap e-mail mezővel, jelszóval és gombbal. Minden elem a parent-hez van rögzítve, kivéve a gombot — az a jelszómező alatt található. Lapos hierarchiát használ — mindhárom elem ugyanazon a szinten.
<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="Bejelentkezés" />
</androidx.constraintlayout.widget.ConstraintLayout>
Minden elem szélessége 0dp (match_constraint), azaz a kényszer start-jától end-jéig terjed, figyelembe véve a vízszintes margót. Ez a match_parent megfelelője hézagokkal, de beágyazás nélkül.
Három gomb, egyenletesen elosztva vízszintesen, szélektől való hézagokkal. A spread_inside lánc a szélső gombokat a szélekre, a középsőt pedig középre helyezi.
<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="Bal" />
<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="Közép" />
<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="Jobb" />
A lánc automatikusan létrejön, amikor az elemek kétirányú kényszerekkel rendelkeznek. A spread_inside mód a lánc bármely elemén beállítható a app:layout_constraintHorizontal_chainStyle="spread_inside" segítségével. Ez kiküszöböli a LinearLayout használatának szükségességét weightSum és layout_weight paraméterekkel.
Két egyenlő oszlop létrehozása egy függőleges Guideline segítségével 50%-nál. A bal elem a parent bal széléhez és jobb szélével a guideline-hoz van rögzítve; a jobb elem — bal szélével a guideline-hoz és a parent jobb széléhez.
<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" />
A 0.5 százalékos Guideline automatikusan alkalmazkodik a képernyő szélességéhez. Tableten és telefonon az oszlopparányok 50/50 maradnak. A bal/jobb elnevezéshez használja a start/end attribútumokat az RTL-kompatibilitás érdekében.
A három fő ViewGroup összehasonlító táblázata Android-fejlesztéshez: ConstraintLayout, LinearLayout és RelativeLayout. Szempontok: rugalmasság, teljesítmény, kód bonyolultsága és alkalmazási területek.
| Jellemző | ConstraintLayout | LinearLayout | RelativeLayout |
|---|---|---|---|
| Beágyazás | Lapos (egy szint) | Beágyazást igényel bonyolult elrendezésekhez | Egy szint, de korlátozott rugalmasság |
| Measure teljesítmény | 2 menet (~40% gyorsabb) | 4+ menet weight esetén | 2 menet |
| Százalékos méretek | Igen (guide_percent, width_percent) | Csak weight/frame segítségével | Nem |
| RTL-támogatás | Beépített (start/end) | Beépített | start/end segítségével (API 17+) |
| Barrier/Group/Flow | Igen (virtuális segítők) | Nem | Nem |
| MotionLayout animációk | Igen | Nem | Nem |
| Mikor használjuk | Minden bonyolult elrendezés, >5 elemes képernyők | Egyszerű egyirányú listák, gombsorok | Egyszerű relatív elrendezések (örökölt kódból) |
Az Android Vitals adatai szerint (Google, 2025) azok az alkalmazások, amelyek a ConstraintLayout-ot használják elsődleges konténerként, átlagosan 18%-kal kevesebb akadó keretet mutatnak a bonyolult képernyők megjelenítésekor, mint a beágyazott LinearLayout-okat használó alkalmazások. Az IT Sectr-nél 2018-ban áttértünk a ConstraintLayout-ra az összes XML-elrendezés szabványaként — ez a képernyőhierarchia átlagos mélységét 4,2-ről 1,8 szintre csökkentette, és 25%-kal felgyorsította az új űrlapok fejlesztését.
Gyakran Ismételt Kérdések
A match_parent a ConstraintLayout-ban a szokásos módon működik — a View-t a szülő méretére nyújtja. A 0dp (match_constraint) azt jelenti, hogy a View mérete a kényszerekből számítódik: ha a bal és jobb kényszerek margóval vannak beállítva, a szélesség = parent — marginLeft — marginRight. Viselkedésbeli különbség: a match_parent figyelmen kívül hagyja a bias-t, és animáció során túlléphet a határokon; a match_constraint helyesen figyelembe veszi az összes korlátozást, és a Google ezt ajánlja elsődleges módként a ConstraintLayout-hoz.
Használja a következő kombinációt: százalékos méretek (layout_constraintWidth_percent) azokhoz az elemekhez, amelyek a képernyő egy részét foglalják el; Guideline százalékokkal a képernyő zónákra osztásához; Barrier a dinamikus tartalomhoz viszonyított pozícionáláshoz; Flow wrapMode-dzsal a kártyák új sorba viteléhez. Alternatív megközelítés — a SlidingPaneLayout használata a ConstraintLayout-tal kombinálva master-detail felületekhez tableteken.
A Jetpack Compose nem használja a ConstraintLayout-ot ViewGroup-ként, de biztosítja a ConstraintLayout Compose verzióját (androidx.constraintlayout:constraintlayout-compose) ugyanazzal az API-val Kotlin DSL-ben: createRefFor(), constrainAs(), linkTo(), chain(), guideFrom(). Ez hasznos olyan bonyolult elrendezésekhez, amelyeket könnyebb kényszerekkel leírni, mint Column/Row segítségével. A Compose-ban azonban ajánlott Column/Row/Box-al kezdeni, és csak akkor áttérni a ConstraintLayout-ra, ha bonyolult relatív pozícionálásra van szükség.
Az Android Studio-ban nyissa meg a Layout Inspector-t (Tools → Layout Inspector), válassza ki a futó alkalmazást, és vigye az egeret a problémás elem fölé. Minden kényszert, margót, padding-et és bias-t látni fog háromdimenziós nézetben. XML-hez használja a Design panelt az elrendezésszerkesztőben — ez sárgával jelöli a kényszerütközéseket, pirossal a kényszerek hiányát. A kódban ellenőrizze, hogy minden View rendelkezik-e két merőleges kényszerrel, különben az elem a (0,0) koordinátákra kerül.
Összefoglalás
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is