Vysvětlujeme podstatu RelativeLayout — ViewGroup v Android SDK pro pozicování podřízených prvků vůči sobě nebo vůči nadřazenému kontejneru. Na rozdíl od LinearLayout, který řadí prvky striktně sekvenčně, RelativeLayout umožňuje umístit libovolný prvek vlevo, vpravo, nad, pod nebo na střed vůči libovolnému jinému prvku podle jeho ID. To dělá RelativeLayout vhodným pro překrývající se a složité rozvržení bez vnořování. Základní pravidla jsou popsána v dokumentaci Android Developers.
Hlavní body
RelativeLayout — ViewGroup, která se objevila v Android SDK od API Level 1, která pozicuje podřízené prvky pomocí deklarativních pravidel (layout rules) vůči rodiči nebo jiným podřízeným prvkům. Každé pravidlo je definováno XML atributem jako android:layout_above, android:layout_below, android:layout_toLeftOf s hodnotou ID cílového prvku.
Před příchodem RelativeLayout byli vývojáři nuceni používat vnořené LinearLayout pro každé nestandardní pozicování — to vedlo k hlubokému vnořování a pomalému vykreslování. RelativeLayout tento problém vyřešil nabídkou relativního pozicování na jedné úrovni hierarchie. Jeho flexibilita je však omezená ve srovnání s moderním ConstraintLayout: RelativeLayout nepodporuje řetězce, bariéry, vodítka a procentuální velikosti.
RelativeLayout má dvě klíčové vlastnosti: jeden průchod onMeasure (na rozdíl od LinearLayout s weight, který vyžaduje dva průchody) a závislost na pořadí deklarace — pokud prvek A odkazuje na prvek B a B je deklarován po A, B musí mít známou velikost v okamžiku měření A. Podle Android Developers Guide (2024) provádí RelativeLayout měření v jednom průchodu, pokud všechna pravidla odkazují na již změřené prvky. V opačném případě je vyžadován druhý průchod, což snižuje výkon.
RelativeLayout je opodstatněný pro jednoduchá rozvržení se 3–7 prvky, kde je vyžadováno relativní pozicování (štítek nad tlačítkem, ikona vpravo od textu, panel v dolní části obrazovky). Pro nové projekty je doporučen ConstraintLayout, ale RelativeLayout se stále široce používá v legacy kódu a knihovnách.
RelativeLayout používá dva typy pravidel: relative-pravidla (pozicování vůči jinému prvku) a align-pravidla (ukotvení k rodiči). Každý podřízený prvek může mít neomezený počet pravidel, ale konfliktní pravidla (např. alignParentTop a below jiného prvku) se řeší ve prospěch posledního deklarovaného v atributu.
Relative-pravidla:
- android:layout_above="@id/target" — spodní okraj prvku je ukotven k hornímu okraji target.
- android:layout_below="@id/target" — horní okraj prvku je ukotven k dolnímu okraji target.
- android:layout_toLeftOf="@id/target" — pravý okraj je ukotven k levému okraji target.
- android:layout_toRightOf="@id/target" — levý okraj je ukotven k pravému okraji target.
- android:layout_toStartOf="@id/target" — analog toLeftOf pro RTL lokalizace.
- android:layout_toEndOf="@id/target" — analog toRightOf pro RTL.
Align-pravidla (k rodiči):
- android:layout_alignParentTop="true" — horní okraj prvku se shoduje s horním okrajem rodiče.
- android:layout_alignParentBottom="true" — spodní okraj se shoduje se spodním okrajem rodiče.
- android:layout_alignParentLeft="true" — levý okraj se shoduje s levým okrajem rodiče.
- android:layout_alignParentRight="true" — pravý okraj se shoduje s pravým okrajem rodiče.
- android:layout_alignParentStart a android:layout_alignParentEnd — pro RTL.
Align-pravidla k jiným prvkům:
- android:layout_alignTop="@id/target" — horní část prvku se shoduje s horní částí target.
- android:layout_alignBottom, android:layout_alignLeft, android:layout_alignRight, android:layout_alignStart, android:layout_alignEnd — podobně.
- android:layout_alignBaseline="@id/target" — zarovnání na základní linii textu (užitečné pro řádky s různými velikostmi písma).
Centrování v RelativeLayout se definuje třemi atributy: android:layout_centerInParent="true" (střed rodiče na obou osách), android:layout_centerHorizontal="true" (střed vodorovně) a android:layout_centerVertical="true" (střed svisle). Centrování je kompatibilní s jinými pravidly: prvek může být vycentrován vodorovně a zároveň ukotven ke spodnímu okraji rodiče.
Pořadí překrývání (Z-order) v RelativeLayout je určeno pořadím deklarace prvků v XML. První deklarovaný prvek se kreslí první (bude dole), poslední — poslední (bude nahoře). Pokud potřebujete změnit pořadí překrývání bez změny XML, použijte android:elevation (od API 21) — prvky s vyšší elevation se kreslí navrchu. Pro verze pod API 21 je pořadí překrývání řízeno pouze pořadím deklarace.
Důležité: RelativeLayout nepodporuje atribut android:elevation pro rodiče — každý prvek spravuje svou vlastní elevation samostatně. V případě konfliktu mezi pravidly pozicování a elevation (např. překrývající se prvky) má elevation prioritu při kreslení, ale ne při pozicování — prvek s vyšší elevation může vizuálně zakrýt jiný, i když jeho pravidla rozvržení jej umísťují vzadu.
Avatar uprostřed nahoře, jméno pod avatarem, status pod jménem, tlačítko akce v dolní části obrazovky. Všechny prvky používají relative-pravidla pro sekvenční ukotvení.
<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="Upravit profil" />
</RelativeLayout>
Avatar je ukotven nahoře pomocí marginTop + centerHorizontal, jméno — pod avatarem pomocí layout_below, status — pod jménem, tlačítko — ke spodnímu okraji rodiče pomocí alignParentBottom. Všechny prvky jsou na sobě nezávislé, neexistují žádné řetězce ani vnořování.
Ikona s červeným odznakem (kruh s číslem) v pravém horním rohu. Odznak je pozicován vůči ikoně pomocí align k jejím okrajům s negativními margin pro překrytí.
<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>
Odznak je ukotven k hornímu a pravému okraji ikony. Negativní margin (-6dp) posouvají odznak ven a vytvářejí efekt přesahující hranici ikony. Toto je populární vzor pro oznámení, který by bez RelativeLayout vyžadoval FrameLayout nebo vlastní kreslení.
Přihlašovací formulář: logo uprostřed nahoře, pole email pod ním, pole hesla pod emailem, tlačítko 'Přihlásit' pod heslem, odkaz 'Registrace' přichycený ke spodní části. Všechny prvky jsou sekvenčně ukotveny pomocí 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="Heslo"
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="Přihlásit" />
<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="Nemáte účet? Zaregistrovat se"
android:textColor="@color/primary" />
</RelativeLayout>
Obrazovka používá 5 prvků na jedné úrovni hierarchie. Tok shora dolů (logo → email → heslo → tlačítko) je zajištěn pomocí layout_below a odkaz je přichycen dole pomocí alignParentBottom. Pro stejnou funkčnost by LinearLayout vyžadoval dva vnořené kontejnery (jeden pro horní skupinu, druhý pro odkaz s weight).
Srovnání dvou ViewGroup pro relativní pozicování: RelativeLayout (klasický, API 1+) a ConstraintLayout (moderní, Jetpack). Kritéria: flexibilita, výkon, podpora RTL a adaptabilita.
| Vlastnost | RelativeLayout | ConstraintLayout |
|---|---|---|
| Procentuální velikosti | Ne (jen pevné a match_parent) | Ano (width_percent, height_percent, guideline_percent) |
| Podpora RTL | Přes start/end (API 17+) | Vestavěná |
| Chain / řetězce | Ne | Ano (spread, spread_inside, packed) |
| Barrier / Group / Flow | Ne | Ano (virtuální pomocníci) |
| MotionLayout animace | Ne | Ano |
| Průchody onMeasure | 1 (bez cyklů závislostí) | 2 (vždy, ale optimalizované) |
| Centrování | centerInParent, centerHorizontal, centerVertical | Přes bias (0.0–1.0) s opačnými constrainty |
| Kdy použít | Legacy kód, jednoduchá rozvržení se 3–7 prvky | Nové projekty, složité obrazovky, adaptivní rozvržení |
RelativeLayout je horší než ConstraintLayout téměř ve všech ohledech, kromě jednoho: je vestavěný v Android SDK od API 1 a nevyžaduje další závislosti. Pro projekty, které stále používají minSdk pod API 14 (Android 4.0), je RelativeLayout jedinou standardní možností pro relativní pozicování. Ve všech ostatních případech Google doporučuje ConstraintLayout.
Často kladené otázky
Nejpravděpodobnější příčina — nedostatečný počet pravidel pozicování. Každý prvek v RelativeLayout musí mít alespoň jedno vodorovné pravidlo (alignParentLeft, toRightOf, centerHorizontal) a jedno svislé (alignParentTop, below, centerVertical). Pokud pravidla chybí, prvek skončí na pozici (0,0) a může být skryt pod jinými prvky nebo mimo obrazovku. Druhou příčinou — cyklická závislost (prvek A je ukotven k B, B je ukotven k A), která vede k nepředvídatelnému chování.
Použijte atribut android:layout_centerInParent="true". Ten vycentruje prvek na obou osách současně. Pokud potřebujete jen vodorovně — android:layout_centerHorizontal="true", jen svisle — android:layout_centerVertical="true". Centrování funguje v kombinaci s margin — prvek bude posunut vůči středu o určenou vzdálenost.
Lze, ale nedoporučuje se. RelativeLayout provádí dva průchody onMeasure při existenci cyklických závislostí, což je o 15–30 % pomalejší než ConstraintLayout v seznamech RecyclerView. Pro rozvržení položek RecyclerView použijte ConstraintLayout — poskytuje plochou hierarchii s minimálním časem měření. Pokud je RelativeLayout již používán v legacy projektu, ujistěte se, že prvky nevytvářejí cyklické závislosti, a změřte FPS rolování pomocí Profile GPU Rendering.
android:layout_margin nastavuje okraje ze všech stran současně. android:layout_marginTop — pouze shora. Specifičtější atribut má prioritu: pokud jsou nastaveny jak layout_margin (16dp), tak layout_marginTop (8dp), horní okraj bude 8dp. V RelativeLayout funguje okraj vzhledem k constraintu, ne vzhledem k sousednímu prvku: layout_marginTop s layout_below="@id/target" — to je vzdálenost od horního okraje prvku ke spodnímu okraji target.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také