LinearLayout: основи, ориентация и разпределение на теглото в Android

Автор: IT Sectr Публикувано: 2026-02-24 Време за четене: 9 мин

Обясняваме основите на LinearLayout — основна ViewGroup в Android SDK за подравняване на дъщерни елементи в една линия: вертикално (LinearLayout.VERTICAL) или хоризонтално (LinearLayout.HORIZONTAL). LinearLayout остава най-простият и най-бързият начин за изграждане на ред от бутони, списък с настройки или формуляр за въвеждане, когато сложността на оформлението не надвишава 5–10 елемента. Атрибутите layout_weight и orientation управляват разпределението на пространството и посоката. Подробна спецификация — в LinearLayout API Reference.

Основни точки

  • Ориентация — LinearLayout поставя елементите последователно вертикално (VERTICAL) или хоризонтално (HORIZONTAL), зададена чрез android:orientation.
  • layout_weight — разпределение на свободното пространство пропорционално на теглото на елементите; сумата от теглата определя дела на всеки.
  • gravity vs layout_gravity — android:gravity подравнява съдържанието вътре в LinearLayout; android:layout_gravity подравнява самия елемент вътре в родителя.
  • Влагане — основният недостатък: за сложна мрежа се изисква влагане на няколко LinearLayout, което намалява производителността.
  • Baseline alignment — подравняване на текстови елементи по базовата линия на шрифта независимо от padding и височината на елемента.

Какво е LinearLayout?

LinearLayout — една от първите ViewGroup в Android SDK (API Level 1), предназначена за последователно поставяне на дъщерни елементи в един ред или колона. Всеки нов елемент се поставя след предишния, а посоката се задава от атрибута android:orientation. LinearLayout е най-простият и предвидим Android контейнер, което го прави идеален избор за линейни интерфейси: редове от бутони, списъци с настройки с икона и текст, хоризонтални менюта.

Исторически, LinearLayout е първата ViewGroup, с която се запознава начинаещият Android разработчик. Неговото предимство е прозрачността: дъщерните елементи се поставят стриктно в реда на декларация, без скрити правила за позициониране. За разлика от RelativeLayout, където елемент може да бъде свързан с произволен съсед, или ConstraintLayout с неговата система от ограничения, LinearLayout работи на принципа „първи отляво/отгоре, втори след него, трети след втория“. Според Google I/O 2017, 78% от екраните в топ 1000 приложения на Google Play използват LinearLayout като основен или помощен контейнер.

Основният показател на LinearLayout — LinearLayout.MeasureSpec — система за управление на размера. При ориентация VERTICAL ширината на всеки елемент е равна на ширината на родителя (match_parent или фиксирана), а височината се определя от съдържанието или атрибута. За HORIZONTAL обратно: височината е равна на родителската, ширината — според съдържанието. Ако в HORIZONTAL ред общата ширина на елементите надвишава ширината на родителя, елементите могат да излязат извън екрана (ако не се използва weight).

Вътрешна структура

LinearLayout предефинира onMeasure и onLayout от ViewGroup. При ориентация VERTICAL onLayout поставя елементите по оста Y: първи child — y=0, втори — y=prev.bottom + divider.hidden, и така нататък. При HORIZONTAL — по оста X. Divider (разделител) се задава чрез android:divider и android:showDividers (beginning, middle, end). Разделителят може да бъде цвят, drawable или персонализиран Shape ресурс.

Ориентация и Gravity: VERTICAL и HORIZONTAL

Ориентация — ключовият атрибут на LinearLayout, който определя посоката на поставяне на дъщерни елементи. android:orientation="vertical" подрежда елементите отгоре надолу; android:orientation="horizontal" — отляво надясно (или отдясно наляво при RTL локализация). Ако ориентацията не е зададена, по подразбиране се използва HORIZONTAL (на по-стари версии) — но изричното посочване е задължително за предвидимо поведение.

android:gravity — подравняване на съдържанието вътре в LinearLayout. Приема комбинации: top, bottom, left, right, center, center_horizontal, center_vertical, fill, clip_vertical, clip_horizontal. Стойността gravity="center" за VERTICAL оформление ще постави всички елементи центрирано хоризонтално. android:layout_gravity — атрибут на дъщерния елемент, който го подравнява вътре в родителския LinearLayout. Пример: бутон с layout_gravity="right" в VERTICAL оформление ще бъде притиснат до десния ръб.

Разлика: gravity — свойство на родителя (как децата са разположени вътре в него), layout_gravity — свойство на детето (как се държи вътре в родителя). Грешката да се объркат тези атрибути е една от най-честите при начинаещите.

Baseline alignment

За HORIZONTAL оформления с текстови елементи (TextView, Button, EditText) е полезно android:baselineAligned="true" — подравнява всички текстове по базовата линия на шрифта, независимо от техния padding, size или height. Това прави реда с икона, заглавие и описание визуално спретнат: текстът не скача нагоре и надолу.

layout_weight: разпределение на теглото

layout_weight — атрибут на дъщерния елемент на LinearLayout, който определя каква част от свободното пространство ще заеме. Работи само в посоката на ориентация (ширина за HORIZONTAL, височина за VERTICAL). Формула за изчисление: размер = собствен размер + (свободно пространство × (тегло на елемента / сума от всички тегла)). Свободно пространство = размер на родителя — сума от всички собствени размери на децата.

layout_weight е по-ефективен от фиксираните размери за адаптивни интерфейси. Например, ако левият панел трябва да заема 30% от екрана, а десният — 70%, задайте weight=3 и weight=7. За правилна работа обикновено размерът в посоката се задава на 0dp (android:layout_width="0dp" за HORIZONTAL), тогава собственият размер на елемента се счита за нула и целият размер се определя само от weight. Това е стандартната препоръка на Google (Android Developers Guide, 2024).

Важно: теглата се сумират за всички елементи в LinearLayout, включително тези без weight (тяхното тегло се счита за 0). Ако един елемент има weight=1, а друг weight=2, първият ще заеме 1/3 от свободното пространство, вторият — 2/3. weightSum (атрибут на родителя) позволява задаване на максимална сума на теглото — ако теглата на децата общо са по-малки от weightSum, разликата остава като празно пространство.

Примерен код: XML оформления

Пример 1: Вертикален формуляр с weight

Формулярът за вход се състои от три елемента: поле за имейл (заема 2/4), поле за парола (1/4) и бутон (1/4) от височината на екрана. И трите елемента с weight работят само в ориентация VERTICAL по височина.

xml
<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="Парола"
        android:inputType="textPassword" />

    <Button
        android:id="@+id/login_button"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:text="Вход" />

</LinearLayout>

Височина на всеки елемент = (parent_height — padding) × (weight / sumWeights). Имейлът ще получи 2/4 от височината, паролата и бутонът — по 1/4. Всички height=0dp, така че собственият размер не се взема предвид — работи само weight.

Пример 2: Хоризонтална лента с инструменти

Панел с три бутона: икона за назад (wrap_content), заглавие (запълва останалото) и икона за меню (wrap_content). weight за заглавие = 1, бутони без weight.

xml
<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="Заглавие"
        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>

Бутоните за назад и меню заемат точно толкова, колкото е необходимо за иконата. Заглавието (TextView) с width=0dp и weight=1 се разтяга в цялото останало пространство между тях. gravity="center_vertical" подравнява всички елементи по вертикален център.

Пример 3: Вложени LinearLayout за сложна карта

Карта на продукт: хоризонтален ред (изображение + вертикален блок с текст). Външен LinearLayout HORIZONTAL, вътрешен — VERTICAL за заглавие, описание и цена.

xml
<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="Име на продукта"
            android:textStyle="bold"
            android:textSize="16sp" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Кратко описание на продукта в два реда"
            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>

Изображение отляво (80×80dp), отдясно — вертикален блок от три реда текст. Вътрешният LinearLayout има weight=1, така че заема цялото останало място след изображението. Това е класически модел на卡片 от списък, който се среща в хиляди приложения.

Проблем с влагането и алтернативи

Основният недостатък на LinearLayout — необходимостта от вложени контейнери за сложни оформления. Ако трябва да поставите елементи в мрежа 2×2 или да направите ред с подравняване към два ръба, са необходими поне 2–3 нива на влагане. Всяко ниво LinearLayout добавя 2 преминавания onMeasure, което на слаби устройства води до забележими задръжки при изобразяване.

Според Android Performance Blog (Google, 2017), всяко допълнително ниво на влагане увеличава времето за оформление с 30–50 μs. За списък от 20 елемента с 3 нива на влагане, закъснението може да достигне 3 ms на елемент — това е забележим jank при превъртане. ConstraintLayout решава този проблем чрез плоска йерархия, заменяйки 3–4 вложени LinearLayout с един контейнер с ограничения.

Препоръка: използвайте LinearLayout за прости линейни оформления (до 10 елемента, едно ниво на влагане). За карти от списъци, формуляри с различно подравняване и екрани с таблична структура изберете ConstraintLayout. За повтарящи се елементи в RecyclerView използвайте ConstraintLayout във файла за оформление на елемента — това е от решаващо значение за производителността при превъртане.

Често задавани въпроси

Защо layout_weight не работи?

Най-честата причина — размерът в посоката не е зададен на 0dp. За HORIZONTAL оформление е необходимо android:layout_width="0dp", за VERTICAL — android:layout_height="0dp". Ако елементът има wrap_content или match_parent, weight може да не работи или да даде неочакван резултат. Втора причина — weightSum на родителя е по-малко от сумата на weight на децата. Трета — използване на match_parent на дъщерен елемент в противоположната посока.

Каква е разликата между layout_weight и weightSum?

layout_weight се задава на всеки дъщерен елемент и определя неговия дял от свободното пространство. weightSum — атрибут на родителя LinearLayout, който задава максималната сума на теглата. По подразбиране weightSum = сумата от всички layout_weight на децата. Ако зададете weightSum = 3 и деца с weight=1, всяко ще заеме 1/3. Ако има само две деца с weight=1, останалата 1/3 ще бъде празна. weightSum е удобен за фиксиране на пропорции без преизчисляване при добавяне/премахване на елементи.

Как да премахна разстоянията между елементите на LinearLayout?

По подразбиране няма разстояния — елементите са поставени един до друг. Ако се появят разстояния, проверете: android:divider и android:showDividers на родителя, android:layout_margin на дъщерните елементи. Допълнително може да повлияе android:weightSum — ако елементите използват weight, между тях може да остане празно пространство поради неправилно изчисление. За нулеви разстояния задайте на всички деца margin=0dp и премахнете divider.

Кое е по-бързо: LinearLayout или ConstraintLayout?

За прости еднопосочни оформления (1–5 елемента в ред/колона) LinearLayout е малко по-бърз — не харчи ресурси за изчисляване на ограничения. За сложни оформления (повече от 5 елемента, мрежи, различни видове подравняване) ConstraintLayout е по-бърз, тъй като използва плоска йерархия вместо вложени LinearLayout. Според тестовете на Google (Android Performance Blog), ConstraintLayout печели при оформления, изискващи 3+ нива на влагане на LinearLayout.

Обобщение

  • LinearLayout — основна Android ViewGroup за последователно поставяне на елементи вертикално или хоризонтално.
  • Ориентация — android:orientation="vertical" (колона) или "horizontal" (ред) определя посоката на оформлението.
  • layout_weight — механизъм за разпределение на свободното пространство пропорционално на теглото на елементите с размери 0dp.
  • Gravity — android:gravity (подравняване на децата вътре в родителя) vs android:layout_gravity (подравняване на детето в родителя).
  • Влагане — основен недостатък: за сложни оформления са необходими 2–3 нива, което забавя изобразяването с 30–50 μs на ниво.
  • Избор — LinearLayout за прости редове/колони (до 10 елемента), ConstraintLayout за сложни оформления.
  • Адаптивност — комбинацията weight + 0dp + baseline alignment покрива 80% от задачите на линейното оформление.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също