Elmagyarázzuk a LinearLayout alapjait — az alapvető ViewGroup-ot az Android SDK-ban a gyermekelemek egy sorba igazításához: függőlegesen (LinearLayout.VERTICAL) vagy vízszintesen (LinearLayout.HORIZONTAL). A LinearLayout marad a legegyszerűbb és leggyorsabb módja egy gombsor, beállításlista vagy beviteli űrlap felépítésének, amikor az elrendezés bonyolultsága nem haladja meg az 5–10 elemet. A layout_weight és orientation attribútumok kezelik a tér elosztását és az irányt. Részletes specifikáció — a LinearLayout API Reference oldalon.
Főbb pontok
LinearLayout — az egyik első ViewGroup az Android SDK-ban (API Level 1), amely a gyermekelemek egymás utáni egy sorba vagy oszlopba helyezésére szolgál. Minden új elem az előző után helyezkedik el, és az irányt az android:orientation attribútum határozza meg. A LinearLayout a legegyszerűbb és legkiszámíthatóbb Android-konténer, ami ideális választássá teszi lineáris interfészekhez: gombsorok, ikonnal és szöveggel ellátott beállításlisták, vízszintes menük.
Történelmileg a LinearLayout az első ViewGroup, amelyet egy kezdő Android-fejlesztő megismer. Előnye az átláthatóság: a gyermekelemek szigorúan a deklaráció sorrendjében helyezkednek el, rejtett pozicionálási szabályok nélkül. Ellentétben a RelativeLayout-tal, ahol egy elem bármely szomszédhoz köthető, vagy a ConstraintLayout-tal a maga kényszerrendszerével, a LinearLayout az 'első balra/fentre, második utána, harmadik a második után' elv szerint működik. A Google I/O 2017 szerint a Google Play top 1000 alkalmazásában a képernyők 78%-a használja a LinearLayout-ot elsődleges vagy kiegészítő konténerként.
A LinearLayout fő metrikája — LinearLayout.MeasureSpec — a méretkezelő rendszer. VERTICAL tájolásnál az egyes elemek szélessége megegyezik a szülő szélességével (match_parent vagy fix), a magasságot pedig a tartalom vagy attribútum határozza meg. HORIZONTAL esetén fordítva: a magasság megegyezik a szülőével, a szélesség — a tartalom szerint. Ha egy HORIZONTAL sorban az elemek teljes szélessége meghaladja a szülő szélességét, az elemek kilóghatnak a képernyőről (ha nem használunk weight-et).
A LinearLayout felülírja az onMeasure és onLayout metódusokat a ViewGroup-ból. VERTICAL tájolásnál az onLayout az elemeket az Y tengely mentén helyezi el: első child — y=0, második — y=prev.bottom + divider.hidden, és így tovább. HORIZONTAL esetén — az X tengely mentén. A Divider (elválasztó) az android:divider és android:showDividers (beginning, middle, end) segítségével állítható be. Az elválasztó lehet szín, drawable vagy egyéni Shape-erőforrás.
Tájolás — a LinearLayout kulcsattribútuma, amely meghatározza a gyermekelemek elhelyezésének irányát. android:orientation="vertical" az elemeket felülről lefelé rendezi; android:orientation="horizontal" — balról jobbra (vagy jobbról balra RTL lokalizációnál). Ha a tájolás nincs beállítva, alapértelmezés szerint a HORIZONTAL használatos (régebbi verziókban) — de a kiszámítható viselkedéshez kötelező a kifejezett megadás.
android:gravity — a tartalom igazítása a LinearLayout-on belül. Kombinációkat fogad: top, bottom, left, right, center, center_horizontal, center_vertical, fill, clip_vertical, clip_horizontal. A gravity="center" érték VERTICAL elrendezésnél az összes elemet vízszintesen középre helyezi. android:layout_gravity — a gyermekelem attribútuma, amely azt igazítja a szülő LinearLayout-on belül. Példa: egy layout_gravity="right" gomb VERTICAL elrendezésben a jobb szélhez lesz nyomva.
Különbség: gravity — a szülő tulajdonsága (hogyan helyezkednek el a gyerekek benne), layout_gravity — a gyermek tulajdonsága (hogyan viselkedik a szülőn belül). Ezen attribútumok összekeverésének hibája az egyik leggyakoribb a kezdők körében.
A HORIZONTAL elrendezéseknél szöveges elemekkel (TextView, Button, EditText) hasznos az android:baselineAligned="true" — ez az összes szöveget a betűtípus alapvonalához igazítja, függetlenül a padding, size vagy height értékétől. Ez vizuálisan rendezetté teszi az ikonból, címből és leírásból álló sort: a szöveg nem ugrál fel és le.
layout_weight — a LinearLayout gyermekelemének attribútuma, amely meghatározza, hogy a szabad tér mekkora részét foglalja el. Csak a tájolás irányában működik (szélesség HORIZONTAL esetén, magasság VERTICAL esetén). Számítási képlet: méret = saját méret + (szabad tér × (elem súlya / összes súly összege)). Szabad tér = szülő mérete — az összes gyermek saját méretének összege.
A layout_weight hatékonyabb, mint a rögzített méretek az adaptív interfészekhez. Például, ha a bal panelnek a képernyő 30%-át, a jobb panelnek pedig 70%-át kell elfoglalnia, állítsa be a weight=3 és weight=7 értékeket. A helyes működéshez általában a méretet az irányban 0dp-re állítják (android:layout_width="0dp" HORIZONTAL esetén), ekkor az elem saját mérete nullának számít, és a teljes méretet csak a weight határozza meg. Ez a Google szokásos ajánlása (Android Developers Guide, 2024).
Fontos: a súlyok a LinearLayout összes elemére összeadódnak, beleértve azokat is, amelyeknek nincs weight beállítva (súlyuk 0-nak számít). Ha az egyik elem weight=1, a másik weight=2, az első a szabad tér 1/3-át foglalja el, a második — 2/3-át. A weightSum (a szülő attribútuma) lehetővé teszi a maximális súlyösszeg beállítását — ha a gyermekek súlyainak összege kisebb, mint weightSum, a különbség üres helyként marad.
A bejelentkezési űrlap három elemből áll: e-mail mező (a képernyőmagasság 2/4-ét foglalja el), jelszó mező (1/4) és gomb (1/4). Mindhárom weight-tel rendelkező elem csak VERTICAL tájolásban működik magasság szerint.
<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="Jelszó"
android:inputType="textPassword" />
<Button
android:id="@+id/login_button"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Bejelentkezés" />
</LinearLayout>
Az egyes elemek magassága = (parent_height — padding) × (weight / sumWeights). Az e-mail a magasság 2/4-ét kapja, a jelszó és a gomb — egyenként 1/4-ét. Mindegyik height=0dp, így a saját méret nem számít — csak a weight működik.
Három gombból álló panel: vissza ikon (wrap_content), cím (kitölti a maradékot) és menü ikon (wrap_content). weight a címhez = 1, gombok weight nélkül.
<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="Cím"
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>
A vissza és menü gombok pontosan annyi helyet foglalnak el, amennyi az ikonhoz kell. A cím (TextView) width=0dp és weight=1 beállítással a köztük lévő összes maradék helyre kitágul. gravity="center_vertical" az összes elemet függőlegesen középre igazítja.
Termékkártya: vízszintes sor (kép + függőleges szövegblokk). Külső LinearLayout HORIZONTAL, belső — VERTICAL a címhez, leíráshoz és árhoz.
<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="Termék neve"
android:textStyle="bold"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Termék rövid leírása két sorban"
android:textSize="14sp"
android:textColor="@color/gray" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1 299 dörzsölés."
android:textSize="18sp"
android:textColor="@color/accent" />
</LinearLayout>
</LinearLayout>
Kép balra (80×80dp), jobbra — három szövegsorból álló függőleges blokk. A belső LinearLayout weight=1-gyel rendelkezik, így elfoglalja a kép után maradt összes helyet. Ez egy klasszikus listakártya-minta, amely több ezer alkalmazásban megtalálható.
A LinearLayout fő hátránya — a beágyazott konténerek szükségessége összetett elrendezéseknél. Ha elemeket kell elhelyezni egy 2×2-es rácsban, vagy egy sort kell létrehozni két szélre igazítással, legalább 2–3 szintű beágyazás szükséges. Minden egyes LinearLayout-szint 2 onMeasure menetet ad hozzá, ami gyenge eszközökön észrevehető akadásokhoz vezet a renderelés során.
Az Android Performance Blog (Google, 2017) szerint minden további beágyazási szint 30–50 μs-mal növeli az elrendezési időt. Egy 20 elemből álló, 3 beágyazási szinttel rendelkező lista esetén a késés elemenként 3 ms lehet — ez észrevehető jank görgetéskor. A ConstraintLayout ezt a problémát lapos hierarchiával oldja meg, 3–4 beágyazott LinearLayout-ot egyetlen kényszerekkel ellátott konténerre cserélve.
Javaslat: használja a LinearLayout-ot egyszerű lineáris elrendezésekhez (legfeljebb 10 elem, egy beágyazási szint). Listakártyákhoz, különböző igazítású űrlapokhoz és táblázatos szerkezetű képernyőkhöz válassza a ConstraintLayout-ot. Az ismétlődő elemekhez a RecyclerView-ben használja a ConstraintLayout-ot az elem layout fájljában — ez kritikus fontosságú a görgetési teljesítmény szempontjából.
Gyakran ismételt kérdések
A leggyakoribb ok — a méret nincs 0dp-re állítva az irányban. HORIZONTAL elrendezéshez android:layout_width="0dp" szükséges, VERTICAL esetén — android:layout_height="0dp". Ha az elem wrap_content vagy match_parent értékkel rendelkezik, a weight nem működhet, vagy váratlan eredményt adhat. A második ok — a szülőn lévő weightSum kisebb, mint a gyermekek súlyainak összege. A harmadik — a match_parent használata egy gyermekelemben az ellenkező irányban.
layout_weight minden egyes gyermekelemre be van állítva, és meghatározza annak részesedését a szabad térből. weightSum — a szülő LinearLayout attribútuma, amely beállítja a súlyok maximális összegét. Alapértelmezés szerint a weightSum = az összes gyermek layout_weight összegével. Ha a weightSum = 3 értéket állítja be és weight=1 gyermekeket, mindegyik 1/3-ot foglal el. Ha csak két weight=1 gyermek van, a fennmaradó 1/3 üres lesz. A weightSum kényelmes az arányok rögzítéséhez az elemek hozzáadásakor/eltávolításakor történő újraszámítás nélkül.
Alapértelmezés szerint nincsenek távolságok — az elemek egymás mellett helyezkednek el. Ha távolságok jelentek meg, ellenőrizze: android:divider és android:showDividers a szülőn, android:layout_margin a gyermekelemeken. Ezenkívül hatással lehet android:weightSum — ha az elemek weight-et használnak, közöttük helytelen számítás miatt üres hely maradhat. Nulla távolságokhoz állítson be minden gyermeknek margin=0dp-t, és távolítsa el a divider-t.
Egyszerű egyirányú elrendezéseknél (1–5 elem sorban/oszlopban) a LinearLayout kissé gyorsabb — nem pazarol erőforrásokat a kényszerek kiszámítására. Összetett elrendezéseknél (több mint 5 elem, rácsok, különböző igazítási típusok) a ConstraintLayout gyorsabb, mivel lapos hierarchiát használ a beágyazott LinearLayout-ok helyett. A Google tesztek szerint (Android Performance Blog) a ConstraintLayout azokon az elrendezéseken nyer, amelyek 3+ szintű LinearLayout beágyazást igényelnek.
Ö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