Vysvětlujeme základy LinearLayout — základní ViewGroup v Android SDK pro zarovnání podřízených prvků do jedné řady: svisle (LinearLayout.VERTICAL) nebo vodorovně (LinearLayout.HORIZONTAL). LinearLayout zůstává nejjednodušším a nejrychlejším způsobem, jak vytvořit řadu tlačítek, seznam nastavení nebo vstupní formulář, když složitost rozvržení nepřesahuje 5–10 prvků. Atributy layout_weight a orientation řídí rozložení prostoru a směr. Podrobná specifikace — v LinearLayout API Reference.
Hlavní body
LinearLayout — jedna z prvních ViewGroup v Android SDK (API Level 1), určená pro sekvenční umísťování podřízených prvků do jedné řady nebo sloupce. Každý nový prvek je umístěn po předchozím a směr je nastaven atributem android:orientation. LinearLayout je nejjednodušší a nejpředvídatelnější Android kontejner, což z něj činí ideální volbu pro lineární rozhraní: řady tlačítek, seznamy nastavení s ikonou a textem, horizontální menu.
Historicky je LinearLayout první ViewGroup, se kterou se seznámí začínající Android vývojář. Jeho výhodou je transparentnost: podřízené prvky jsou umístěny striktně v pořadí deklarace, bez skrytých pravidel pro pozicování. Na rozdíl od RelativeLayout, kde může být prvek připojen k libovolnému sousedovi, nebo ConstraintLayout s jeho systémem omezení, LinearLayout funguje na principu 'první vlevo/nahoře, druhý po něm, třetí po druhém'. Podle Google I/O 2017 používá 78% obrazovek v top 1000 aplikacích Google Play LinearLayout jako hlavní nebo pomocný kontejner.
Hlavní metrika LinearLayout — LinearLayout.MeasureSpec — systém správy velikosti. Při orientaci VERTICAL je šířka každého prvku rovna šířce rodiče (match_parent nebo pevná) a výška je určena obsahem nebo atributem. Pro HORIZONTAL obráceně: výška je rovna rodičovské, šířka — podle obsahu. Pokud v HORIZONTAL řadě celková šířka prvků překročí šířku rodiče, prvky mohou vyčnívat z obrazovky (pokud se nepoužije weight).
LinearLayout přepisuje onMeasure a onLayout z ViewGroup. Při orientaci VERTICAL umísťuje onLayout prvky na ose Y: první child — y=0, druhý — y=prev.bottom + divider.hidden, a tak dále. Při HORIZONTAL — na ose X. Divider (oddělovač) se nastavuje pomocí android:divider a android:showDividers (beginning, middle, end). Oddělovač může být barva, drawable nebo vlastní Shape zdroj.
Orientace — klíčový atribut LinearLayout, který určuje směr umísťování podřízených prvků. android:orientation="vertical" řadí prvky shora dolů; android:orientation="horizontal" — zleva doprava (nebo zprava doleva při RTL lokalizaci). Pokud orientace není nastavena, standardně se používá HORIZONTAL (ve starších verzích) — ale explicitní uvedení je povinné pro předvídatelné chování.
android:gravity — zarovnání obsahu uvnitř LinearLayout. Přijímá kombinace: top, bottom, left, right, center, center_horizontal, center_vertical, fill, clip_vertical, clip_horizontal. Hodnota gravity="center" pro VERTICAL rozvržení umístí všechny prvky na střed horizontálně. android:layout_gravity — atribut podřízeného prvku, který jej zarovnává uvnitř rodičovského LinearLayout. Příklad: tlačítko s layout_gravity="right" ve VERTICAL rozvržení bude přitisknuto k pravému okraji.
Rozdíl: gravity — vlastnost rodiče (jak jsou děti umístěny uvnitř), layout_gravity — vlastnost dítěte (jak se chová uvnitř rodiče). Chyba záměny těchto atributů je jednou z nejčastějších u začátečníků.
Pro HORIZONTAL rozvržení s textovými prvky (TextView, Button, EditText) je užitečné android:baselineAligned="true" — zarovnává všechny texty podle základní linie písma, nezávisle na jejich padding, size nebo height. Díky tomu vypadá řada s ikonou, nadpisem a popisem vizuálně úhledně: text neskáče nahoru a dolů.
layout_weight — atribut podřízeného prvku LinearLayout, který určuje, jakou část volného prostoru zabere. Funguje pouze ve směru orientace (šířka pro HORIZONTAL, výška pro VERTICAL). Vzorec výpočtu: velikost = vlastní velikost + (volný prostor × (váha prvku / součet všech vah)). Volný prostor = velikost rodiče — součet všech vlastních velikostí dětí.
layout_weight je efektivnější než pevné velikosti pro adaptivní rozhraní. Například, pokud levý panel má zabírat 30% obrazovky a pravý — 70%, nastavte weight=3 a weight=7. Pro správnou funkci se obvykle nastavuje velikost ve směru na 0dp (android:layout_width="0dp" pro HORIZONTAL), pak je vlastní velikost prvku považována za nulovou a celá velikost je určena pouze weight. Toto je standardní doporučení Google (Android Developers Guide, 2024).
Důležité: váhy se sčítají pro všechny prvky v LinearLayout, včetně těch bez weight (jejich váha je považována za 0). Pokud má jeden prvek weight=1 a druhý weight=2, první zabere 1/3 volného prostoru, druhý — 2/3. weightSum (atribut rodiče) umožňuje nastavit maximální součet vah — pokud jsou váhy dětí v součtu menší než weightSum, rozdíl zůstává jako prázdný prostor.
Přihlašovací formulář se skládá ze tří prvků: pole email (zabírá 2/4), pole hesla (1/4) a tlačítko (1/4) výšky obrazovky. Všechny tři prvky s weight fungují pouze v orientaci VERTICAL po výšce.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<EditText
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:hint="Email" />
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:hint="Heslo"
android:inputType="textPassword" />
<Button
android:id="@+id/login_button"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Přihlásit se" />
</LinearLayout>
Výška každého prvku = (parent_height — padding) × (weight / sumWeights). email získá 2/4 výšky, heslo a tlačítko — každý 1/4. Všechna height=0dp, takže vlastní velikost se nebere v úvahu — funguje pouze weight.
Panel se třemi tlačítky: ikona zpět (wrap_content), nadpis (vyplní zbytek) a ikona menu (wrap_content). weight pro nadpis = 1, tlačítka bez weight.
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="56dp"
android:gravity="center_vertical">
<ImageButton
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_back" />
<TextView
android:id="@+id/toolbar_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Nadpis"
android:textSize="18sp" />
<ImageButton
android:id="@+id/btn_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_more_vert" />
</LinearLayout>
Tlačítka zpět a menu zabírají přesně tolik, kolik je potřeba pro ikonu. Nadpis (TextView) s width=0dp a weight=1 se roztáhne na veškerý zbývající prostor mezi nimi. gravity="center_vertical" zarovnává všechny prvky na svislý střed.
Karta produktu: vodorovná řada (obrázek + svislý blok textu). Vnější LinearLayout HORIZONTAL, vnitřní — VERTICAL pro nadpis, popis a cenu.
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp">
<ImageView
android:layout_width="80dp"
android:layout_height="80dp"
android:src="@drawable/product_image"
android:scaleType="centerCrop" />
<LinearLayout
android:orientation="vertical"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="12dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Název produktu"
android:textStyle="bold"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Stručný popis produktu ve dvou řádcích"
android:textSize="14sp"
android:textColor="@color/gray" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1 299 rub."
android:textSize="18sp"
android:textColor="@color/accent" />
</LinearLayout>
</LinearLayout>
Obrázek vlevo (80×80dp), vpravo — svislý blok tří řádků textu. Vnitřní LinearLayout má weight=1, takže zabírá veškerý zbývající prostor po obrázku. Toto je klasický vzor karty seznamu, který se vyskytuje v tisících aplikací.
Hlavní nevýhoda LinearLayout — potřeba vnořených kontejnerů pro složitá rozvržení. Pokud je třeba umístit prvky do mřížky 2×2 nebo vytvořit řadu se zarovnáním na dva okraje, jsou zapotřebí nejméně 2–3 úrovně vnoření. Každá úroveň LinearLayout přidává 2 průchody onMeasure, což na slabých zařízeních vede k znatelným zasekáváním při vykreslování.
Podle Android Performance Blog (Google, 2017) každá další úroveň vnoření zvyšuje čas rozvržení o 30–50 μs. Pro seznam 20 prvků se 3 úrovněmi vnoření může zpoždění dosáhnout 3 ms na prvek — to je znatelný jank při rolování. ConstraintLayout řeší tento problém pomocí ploché hierarchie, nahrazuje 3–4 vnořené LinearLayout jedním kontejnerem s omezeními.
Doporučení: používejte LinearLayout pro jednoduchá lineární rozvržení (do 10 prvků, jedna úroveň vnoření). Pro karty seznamů, formuláře s různým zarovnáním a obrazovky s tabulkovou strukturou zvolte ConstraintLayout. Pro opakující se prvky v RecyclerView používejte ConstraintLayout v souboru rozvržení prvku — to je zásadní pro výkon rolování.
Často kladené otázky
Nejčastější příčina — není nastavena velikost ve směru na 0dp. Pro rozvržení HORIZONTAL je potřeba android:layout_width="0dp", pro VERTICAL — android:layout_height="0dp". Pokud má prvek wrap_content nebo match_parent, weight nemusí fungovat nebo může dát neočekávaný výsledek. Druhá příčina — weightSum na rodiči je menší než součet weight dětí. Třetí — použití match_parent na podřízeném prvku v opačném směru.
layout_weight se nastavuje na každém podřízeném prvku a určuje jeho podíl na volném prostoru. weightSum — atribut rodiče LinearLayout, který nastavuje maximální součet vah. Standardně weightSum = součtu všech layout_weight dětí. Pokud nastavíte weightSum = 3 a děti s weight=1, každý zabere 1/3. Pokud jsou jen dvě děti s weight=1, zbývající 1/3 bude prázdná. weightSum je vhodný pro fixaci proporcí bez přepočítávání při přidávání/odebírání prvků.
Standardně nejsou žádné mezery — prvky jsou umístěny těsně vedle sebe. Pokud se mezery objevily, zkontrolujte: android:divider a android:showDividers na rodiči, android:layout_margin na podřízených prvcích. Dodatečně může ovlivnit android:weightSum — pokud prvky používají weight, může mezi nimi zůstat prázdný prostor kvůli nesprávnému výpočtu. Pro nulové mezery nastavte všem dětem margin=0dp a odstraňte divider.
Pro jednoduchá jednosměrná rozvržení (1–5 prvků v řadě/sloupci) LinearLayout je o něco rychlejší — neplýtvá prostředky na výpočet omezení. Pro složitá rozvržení (více než 5 prvků, mřížky, různé typy zarovnání) ConstraintLayout je rychlejší, protože používá plochou hierarchii místo vnořených LinearLayout. Podle testů Google (Android Performance Blog) vítězí ConstraintLayout na rozvrženích vyžadujících 3+ úrovně vnoření LinearLayout.
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é