Објашњавамо суштину RelativeLayout — ViewGroup у Android SDK за позиционирање подређених елемената у односу један на други или у односу на родитељски контејнер. За разлику од LinearLayout, који распоређује елементе строго секвенцијално, RelativeLayout омогућава постављање било ког елемента лево, десно, изнад, испод или у центру у односу на било који други елемент по његовом ID-у. То чини RelativeLayout погодним за преклапајуће и сложене распореде без угњеждавања. Основна правила описана су у документацији Android Developers.
Главно
RelativeLayout — ViewGroup, појављена у Android SDK од API Level 1, која позиционира подређене елементе кроз декларативна правила (layout rules) у односу на родитеља или друге подређене елементе. Свако правило се задаје XML атрибутом попут android:layout_above, android:layout_below, android:layout_toLeftOf са вредношћу ID-а циљног елемента.
Пре појаве RelativeLayout, програмери су били принуђени да користе угњеждене LinearLayout за свако нестандардно позиционирање — то је доводило до дубоког угњеждавања и спорог приказивања. RelativeLayout је решио овај проблем нудећи релативно позиционирање на једном нивоу хијерархије. Међутим, његова флексибилност је ограничена у поређењу са модерним ConstraintLayout: RelativeLayout не подржава ланце, баријере, водиље и процентуалне величине.
RelativeLayout има две кључне карактеристике: један пролаз onMeasure (за разлику од LinearLayout са weight, који захтева два пролаза) и зависност од редоследа декларисања — ако се елемент A позива на елемент B, а B је декларисан после A, B мора имати познату величину у тренутку мерења A. Према Android Developers Guide (2024), RelativeLayout врши мерење у једном пролазу ако се сва правила позивају на већ измерене елементе. У супротном, потребан је други пролаз, што смањује перформансе.
RelativeLayout је оправдан за једноставне распореде са 3–7 елемената, где је потребно релативно позиционирање (натпис изнад дугмета, икона десно од текста, панел на дну екрана). За нове пројекте препоручује се ConstraintLayout, али се RelativeLayout још увек широко користи у старом коду и библиотекама.
RelativeLayout користи две врсте правила: relative-правила (позиционирање у односу на други елемент) и align-правила (причвршћивање за родитеља). Сваки подређени елемент може имати неограничен број правила, али сукобљена правила (нпр. alignParentTop и below другог елемента) решавају се у корист последњег декларисаног у атрибуту.
Relative-правила:
- android:layout_above="@id/target" — доња ивица елемента причвршћена је за горњу ивицу target.
- android:layout_below="@id/target" — горња ивица елемента причвршћена је за доњу ивицу target.
- android:layout_toLeftOf="@id/target" — десна ивица причвршћена је за леву ивицу target.
- android:layout_toRightOf="@id/target" — лева ивица причвршћена је за десну ивицу target.
- android:layout_toStartOf="@id/target" — аналог toLeftOf за RTL локализације.
- android:layout_toEndOf="@id/target" — аналог toRightOf за RTL.
Align-правила (ка родитељу):
- android:layout_alignParentTop="true" — горња ивица елемента се поклапа са горњом ивицом родитеља.
- android:layout_alignParentBottom="true" — доња ивица се поклапа са доњом ивицом родитеља.
- android:layout_alignParentLeft="true" — лева ивица се поклапа са левом ивицом родитеља.
- android:layout_alignParentRight="true" — десна ивица се поклапа са десном ивицом родитеља.
- android:layout_alignParentStart и android:layout_alignParentEnd — за RTL.
Align-правила ка другим елементима:
- android:layout_alignTop="@id/target" — врх елемента се поклапа са врхом target.
- android:layout_alignBottom, android:layout_alignLeft, android:layout_alignRight, android:layout_alignStart, android:layout_alignEnd — слично.
- android:layout_alignBaseline="@id/target" — поравнање по базној линији текста (корисно за редове са различитим величинама фонта).
Центрирање у RelativeLayout се задаје са три атрибута: android:layout_centerInParent="true" (центар родитеља по обе осе), android:layout_centerHorizontal="true" (центар по хоризонтали) и android:layout_centerVertical="true" (центар по вертикали). Центрирање је компатибилно са другим правилима: елемент може бити центриран хоризонтално и истовремено причвршћен за доњу ивицу родитеља.
Редослед преклапања (Z-order) у RelativeLayout-у се одређује редоследом декларисања елемената у XML-у. Први декларисани елемент се црта први (биће ниже), последњи — последњи (биће више). Ако треба да промените редослед преклапања без промене XML-а, користите android:elevation (од API 21) — елементи са већом elevation цртају се преко. За верзије испод API 21, редослед преклапања се регулише само редоследом декларисања.
Важно: RelativeLayout не подржава атрибут android:elevation за родитеља — сваки елемент управља својом elevation самостално. У случају сукоба правила позиционирања и elevation (нпр. елементи који се преклапају) elevation има приоритет за цртање, али не и за позиционирање — елемент са већом elevation може визуелно прекрити други, чак и ако његова layout правила постављају „иза”.
Аватар у центру горе, име испод аватара, статус испод имена, дугме за акцију на дну екрана. Сви елементи користе relative-правила за секвенцијално причвршћивање.
<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="Иван Иванов"
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="Онлајн"
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="Уреди профил" />
</RelativeLayout>
Аватар је причвршћен за врх путем marginTop + centerHorizontal, име — испод аватара кроз layout_below, статус — испод имена, дугме — за доњу ивицу родитеља кроз alignParentBottom. Сви елементи су независни један од другог, нема ланаца или угњеждавања.
Икона са црвеном значком (круг са бројем) у горњем десном углу. Значка се позиционира у односу на икону кроз align ка њеним ивицама са негативним margin за преклапање.
<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>
Значка је причвршћена за горњу и десну ивицу иконе. Негативни margin (-6dp) померају значку напоље, стварајући ефекат прекорачења ивице иконе. Ово је популарни образац за обавештења који би без RelativeLayout захтевао FrameLayout или прилагођено цртање.
Формулар за пријаву: лого у центру горе, поље за емаил испод њега, поље за лозинку испод емаила, дугме „Пријава” испод лозинке, линк „Регистрација” причвршћен за дно. Сви елементи су секвенцијално причвршћени кроз 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="Лозинка"
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="Пријава" />
<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="Немате налог? Региструјте се"
android:textColor="@color/primary" />
</RelativeLayout>
Екран користи 5 елемената на истом нивоу хијерархије. Ток од врха до дна (лого → емаил → лозинка → дугме) обезбеђен је кроз layout_below, а линк је причвршћен за дно кроз alignParentBottom. За исту функционалност LinearLayout би захтевао два угњеждена контејнера (један за горњу групу, други за линк са weight).
Поређење две ViewGroup за релативно позиционирање: RelativeLayout (класичан, API 1+) и ConstraintLayout (модеран, Jetpack). Критеријуми: флексибилност, перформансе, RTL подршка и адаптивност.
| Карактеристика | RelativeLayout | ConstraintLayout |
|---|---|---|
| Процентуалне величине | Не (само фиксне и match_parent) | Да (width_percent, height_percent, guideline_percent) |
| RTL подршка | Кроз start/end (API 17+) | Уграђена |
| Chain / ланци | Не | Да (spread, spread_inside, packed) |
| Barrier / Group / Flow | Не | Да (виртуелни помоћници) |
| MotionLayout анимације | Не | Да |
| Пролази onMeasure | 1 (без циклуса зависности) | 2 (увек, али оптимизовани) |
| Центрирање | centerInParent, centerHorizontal, centerVertical | Кроз bias (0.0–1.0) са супротним констрејнтима |
| Када користити | Стари код, једноставни распореди са 3–7 елемената | Нови пројекти, сложени екрани, адаптивни распореди |
RelativeLayout је инфериоран у односу на ConstraintLayout практично по свим параметрима, осим једног: уграђен је у Android SDK од API 1 и не захтева додатне зависности. За пројекте који још увек користе minSdk испод API 14 (Android 4.0), RelativeLayout је једина стандардна опција за релативно позиционирање. У свим осталим случајевима Google препоручује ConstraintLayout.
Често постављана питања
Највероватнији разлог — недостатак довољног броја правила позиционирања. Сваки елемент у RelativeLayout мора имати бар једно правило по хоризонтали (alignParentLeft, toRightOf, centerHorizontal) и једно по вертикали (alignParentTop, below, centerVertical). Ако нема правила, елемент се налази на позицији (0,0) и може бити сакривен испод других елемената или ван екрана. Други разлог — циклична зависност (елемент A је причвршћен за B, B за A), која доводи до непредвидивог понашања.
Користите атрибут android:layout_centerInParent="true". Он центрира елемент по обе осе истовремено. Ако вам треба само по хоризонтали — android:layout_centerHorizontal="true", само по вертикали — android:layout_centerVertical="true". Центрирање ради у комбинацији са margin — елемент ће бити померен у односу на центар за наведени размак.
Може, али се не препоручује. RelativeLayout врши два пролаза onMeasure при постојању цикличних зависности, што је 15–30% спорије од ConstraintLayout у RecyclerView листама. За распореде ставки RecyclerView користите ConstraintLayout — он обезбеђује равну хијерархију са минималним временом мерења. Ако се RelativeLayout већ користи у старом пројекту, уверите се да елементи не стварају цикличне зависности и измерите FPS скроловања кроз Profile GPU Rendering.
android:layout_margin поставља маргине са свих страна истовремено. android:layout_marginTop — само одозго. Приоритет има специфичнији атрибут: ако су постављени и layout_margin (16dp) и layout_marginTop (8dp), горња маргина ће бити 8dp. У RelativeLayout-у маргина ради у односу на констрејнт, а не у односу на суседни елемент: layout_marginTop уз layout_below="@id/target" — то је размак од горње ивице елемента до доње ивице target.
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође