Explicăm esența RelativeLayout — ViewGroup în Android SDK pentru poziționarea elementelor copil relativ unul la altul sau la containerul părinte. Spre deosebire de LinearLayout, care aranjează elementele strict secvențial, RelativeLayout permite plasarea oricărui element la stânga, dreapta, deasupra, dedesubtul sau în centrul oricărui alt element după ID-ul său. Acest lucru face RelativeLayout convenabil pentru machete suprapuse și complexe fără imbricare. Regulile de bază sunt descrise în documentația Android Developers.
Principalele
RelativeLayout — ViewGroup, apărută în Android SDK începând cu API Level 1, care poziționează elementele copil prin reguli declarative (layout rules) relativ la părinte sau la alte elemente copil. Fiecare regulă este definită de un atribut XML precum android:layout_above, android:layout_below, android:layout_toLeftOf cu valoarea ID-ului elementului țintă.
Înainte de apariția RelativeLayout, dezvoltatorii erau nevoiți să folosească LinearLayout-uri imbricate pentru fiecare poziționare nestandard — aceasta ducea la o imbricare profundă și randare lentă. RelativeLayout a rezolvat această problemă, oferind poziționare relativă la un singur nivel de ierarhie. Cu toate acestea, flexibilitatea sa este limitată în comparație cu ConstraintLayout modern: RelativeLayout nu suportă lanțuri, bariere, ghidaje și dimensiuni procentuale.
RelativeLayout are două caracteristici cheie: un singur pas onMeasure (spre deosebire de LinearLayout cu weight, care necesită doi pași) și dependența de ordinea declarării — dacă elementul A se referă la elementul B, iar B este declarat după A, B trebuie să aibă o dimensiune cunoscută în momentul măsurării lui A. Conform Android Developers Guide (2024), RelativeLayout execută măsurarea într-un singur pas dacă toate regulile se referă la elemente deja măsurate. În caz contrar, este necesar un al doilea pas, ceea ce reduce performanța.
RelativeLayout este justificat pentru machete simple cu 3–7 elemente, unde este necesară poziționarea relativă (etichetă deasupra butonului, pictogramă la dreapta textului, panou în partea de jos a ecranului). Pentru proiecte noi este recomandat ConstraintLayout, dar RelativeLayout este încă utilizat pe scară largă în codul vechi și biblioteci.
RelativeLayout folosește două tipuri de reguli: reguli relative (poziționare față de un alt element) și reguli align (ancorare la părinte). Fiecare element copil poate avea un număr nelimitat de reguli, dar regulile conflictuale (de exemplu, alignParentTop și below altui element) se rezolvă în favoarea ultimei declarate în atribut.
Reguli relative:
- android:layout_above="@id/target" — marginea inferioară a elementului este ancorată de marginea superioară a target.
- android:layout_below="@id/target" — marginea superioară a elementului este ancorată de marginea inferioară a target.
- android:layout_toLeftOf="@id/target" — marginea dreaptă este ancorată de marginea stângă a target.
- android:layout_toRightOf="@id/target" — marginea stângă este ancorată de marginea dreaptă a target.
- android:layout_toStartOf="@id/target" — analog toLeftOf pentru localizări RTL.
- android:layout_toEndOf="@id/target" — analog toRightOf pentru RTL.
Reguli align (la părinte):
- android:layout_alignParentTop="true" — marginea superioară a elementului coincide cu marginea superioară a părintelui.
- android:layout_alignParentBottom="true" — marginea inferioară coincide cu marginea inferioară a părintelui.
- android:layout_alignParentLeft="true" — marginea stângă coincide cu marginea stângă a părintelui.
- android:layout_alignParentRight="true" — marginea dreaptă coincide cu marginea dreaptă a părintelui.
- android:layout_alignParentStart și android:layout_alignParentEnd — pentru RTL.
Reguli align la alte elemente:
- android:layout_alignTop="@id/target" — partea superioară a elementului coincide cu partea superioară a target.
- android:layout_alignBottom, android:layout_alignLeft, android:layout_alignRight, android:layout_alignStart, android:layout_alignEnd — similar.
- android:layout_alignBaseline="@id/target" — aliniere la linia de bază a textului (util pentru rânduri cu dimensiuni de font diferite).
Centrarea în RelativeLayout se definește prin trei atribute: android:layout_centerInParent="true" (centrul părintelui pe ambele axe), android:layout_centerHorizontal="true" (centrul pe orizontală) și android:layout_centerVertical="true" (centrul pe verticală). Centrarea este compatibilă cu alte reguli: un element poate fi centrat pe orizontală și în același timp ancorat de marginea inferioară a părintelui.
Ordinea de suprapunere (Z-order) în RelativeLayout este determinată de ordinea declarării elementelor în XML. Primul element declarat este desenat primul (va fi mai jos), ultimul — ultimul (va fi mai sus). Dacă trebuie să schimbați ordinea de suprapunere fără a modifica XML-ul, utilizați android:elevation (începând cu API 21) — elementele cu elevation mai mare se desenează deasupra. Pentru versiunile sub API 21, ordinea de suprapunere se reglează doar prin ordinea declarării.
Important: RelativeLayout nu suportă atributul android:elevation pentru părinte — fiecare element își gestionează propria elevation. În caz de conflict între regulile de poziționare și elevation (de exemplu, elemente suprapuse), elevation are prioritate la desenare, dar nu la poziționare — un element cu elevation mai mare poate acoperi vizual altul, chiar dacă regulile sale de layout îl plasează „în spate”.
Avatarul în centrul sus, numele sub avatar, statusul sub nume, butonul de acțiune în partea de jos a ecranului. Toate elementele folosesc reguli relative pentru ancorare secvențială.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/avatar"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="32dp"
android:src="@drawable/avatar_placeholder" />
<TextView
android:id="@+id/user_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/avatar"
android:layout_centerHorizontal="true"
android:layout_marginTop="12dp"
android:text="Ivan Ivanov"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/user_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/user_name"
android:layout_centerHorizontal="true"
android:text="Online"
android:textColor="@color/green" />
<Button
android:id="@+id/edit_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="24dp"
android:text="Editează profilul" />
</RelativeLayout>
Avatarul este ancorat sus prin marginTop + centerHorizontal, numele — sub avatar prin layout_below, statusul — sub nume, butonul — la marginea inferioară a părintelui prin alignParentBottom. Toate elementele sunt independente unele de altele, nu există lanțuri sau imbricare.
Pictogramă cu o insignă roșie (cerc cu număr) în colțul din dreapta sus. Insigna este poziționată relativ la pictogramă prin align la marginile sale cu margini negative pentru suprapunere.
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/icon"
android:layout_width="48dp"
android:layout_height="48dp"
android:src="@drawable/ic_notification" />
<TextView
android:id="@+id/badge"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignTop="@+id/icon"
android:layout_alignRight="@+id/icon"
android:layout_marginTop="-6dp"
android:layout_marginRight="-6dp"
android:gravity="center"
android:background="@drawable/badge_background"
android:text="3"
android:textColor="@android:color/white"
android:textSize="10sp" />
</RelativeLayout>
Insigna este ancorată de marginea superioară și dreaptă a pictogramei. Marginile negative (-6dp) deplasează insigna în exterior, creând un efect de depășire a marginii pictogramei. Acesta este un model popular pentru notificări, care fără RelativeLayout ar necesita FrameLayout sau desenare personalizată.
Formular de autentificare: logo-ul centrat sus, câmpul email sub el, câmpul parolă sub email, butonul „Autentificare” sub parolă, linkul „Înregistrare” lipit de jos. Toate elementele sunt ancorate secvențial prin layout_below.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="24dp">
<TextView
android:id="@+id/logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="48dp"
android:text="MyApp"
android:textSize="32sp"
android:textStyle="bold" />
<EditText
android:id="@+id/email_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/logo"
android:layout_marginTop="32dp"
android:hint="Email" />
<EditText
android:id="@+id/password_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/email_input"
android:layout_marginTop="16dp"
android:hint="Parolă"
android:inputType="textPassword" />
<Button
android:id="@+id/login_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/password_input"
android:layout_marginTop="24dp"
android:text="Autentificare" />
<TextView
android:id="@+id/register_link"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="16dp"
android:text="Nu ai cont? Înregistrează-te"
android:textColor="@color/primary" />
</RelativeLayout>
Ecranul folosește 5 elemente la același nivel de ierarhie. Fluxul de sus în jos (logo → email → parolă → buton) este asigurat prin layout_below, iar linkul este lipit de jos prin alignParentBottom. Pentru aceeași funcționalitate, LinearLayout ar necesita două containere imbricate (unul pentru grupul de sus, al doilea pentru link cu weight).
Comparație a două ViewGroup pentru poziționare relativă: RelativeLayout (clasic, API 1+) și ConstraintLayout (modern, Jetpack). Criterii: flexibilitate, performanță, suport RTL și adaptabilitate.
| Caracteristică | RelativeLayout | ConstraintLayout |
|---|---|---|
| Dimensiuni procentuale | Nu (doar fixe și match_parent) | Da (width_percent, height_percent, guideline_percent) |
| Suport RTL | Prin start/end (API 17+) | Integrat |
| Chain / lanțuri | Nu | Da (spread, spread_inside, packed) |
| Barrier / Group / Flow | Nu | Da (asistenți virtuali) |
| Animații MotionLayout | Nu | Da |
| Pași onMeasure | 1 (fără cicluri de dependență) | 2 (întotdeauna, dar optimizați) |
| Centrare | centerInParent, centerHorizontal, centerVertical | Prin bias (0.0–1.0) cu constrângeri opuse |
| Când să folosiți | Cod vechi, machete simple cu 3–7 elemente | Proiecte noi, ecrane complexe, machete adaptive |
RelativeLayout este inferior ConstraintLayout practic în toate aspectele, cu excepția unuia: este încorporat în Android SDK de la API 1 și nu necesită dependențe suplimentare. Pentru proiectele care încă folosesc minSdk sub API 14 (Android 4.0), RelativeLayout este singura opțiune standard pentru poziționare relativă. În toate celelalte cazuri, Google recomandă ConstraintLayout.
Întrebări frecvente
Cea mai probabilă cauză — lipsa unui număr suficient de reguli de poziționare. Fiecare element din RelativeLayout trebuie să aibă cel puțin o regulă pe orizontală (alignParentLeft, toRightOf, centerHorizontal) și una pe verticală (alignParentTop, below, centerVertical). Dacă nu există reguli, elementul ajunge în poziția (0,0) și poate fi ascuns sub alte elemente sau în afara ecranului. A doua cauză — dependența ciclică (elementul A este ancorat de B, B este ancorat de A), care duce la un comportament imprevizibil.
Folosiți atributul android:layout_centerInParent="true". Acesta centrează elementul pe ambele axe simultan. Dacă aveți nevoie doar pe orizontală — android:layout_centerHorizontal="true", doar pe verticală — android:layout_centerVertical="true". Centrarea funcționează împreună cu margin — elementul va fi deplasat relativ la centru cu spațiul specificat.
Se poate, dar nu este recomandat. RelativeLayout execută doi pași onMeasure în prezența dependențelor ciclice, ceea ce este cu 15–30% mai lent decât ConstraintLayout în listele RecyclerView. Pentru machetele de iteme RecyclerView, folosiți ConstraintLayout — acesta asigură o ierarhie plată cu timp minim de măsurare. Dacă RelativeLayout este deja utilizat într-un proiect vechi, asigurați-vă că elementele nu creează dependențe ciclice și măsurați FPS-ul derulării prin Profile GPU Rendering.
android:layout_margin setează margini din toate părțile simultan. android:layout_marginTop — doar de sus. Prioritate are atributul mai specific: dacă sunt setate atât layout_margin (16dp), cât și layout_marginTop (8dp), marginea de sus va fi 8dp. În RelativeLayout, marginea funcționează relativ la constrângere, nu la elementul vecin: layout_marginTop cu layout_below="@id/target" — este distanța de la marginea superioară a elementului până la marginea inferioară a target.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și