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, що знижує продуктивність.
  • Вирівнювання за базовою лінією — вирівнювання текстових елементів за базовою лінією шрифту незалежно від 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. Розділювач задається через 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 — властивість дитини (як вона поводиться всередині батька). Помилка — переплутати ці атрибути — одна з найчастіших у початківців.

Вирівнювання за базовою лінією

Для 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

Форма логіну складається з трьох елементів: поле email (займає 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). email отримає 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 руб."
            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), кожен додатковий рівень вкладеності збільшує час layout на 30–50 мкс. Для списку з 20 елементів з 3 рівнями вкладеності затримка може досягати 3 мс на елемент — це помітний jank при скролі. ConstraintLayout вирішує цю проблему через плоску ієрархію, замінюючи 3–4 вкладених LinearLayout одним контейнером з констрейнтами.

Рекомендація: використовуйте LinearLayout для простих лінійних макетів (до 10 елементів, один рівень вкладеності). Для карток списків, форм з різним вирівнюванням та екранів з табличною структурою вибирайте ConstraintLayout. Для повторюваних елементів в RecyclerView використовуйте ConstraintLayout в layout-файлі елемента — це критично для продуктивності скролу.

Часті запитання

Чому 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, а children з 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 — базова ViewGroup Android для послідовного розміщення елементів по вертикалі або горизонталі.
  • Орієнтація — android:orientation="vertical" (колонка) або "horizontal" (рядок) визначає напрямок розкладки.
  • layout_weight — механізм розподілу вільного простору пропорційно вазі елементів з розмірами в 0dp.
  • Gravity — android:gravity (вирівнювання дітей всередині батька) vs android:layout_gravity (вирівнювання дитини в батьку).
  • Вкладеність — головний недолік: для складних макетів потрібно 2–3 рівні, що сповільнює відображення на 30–50 мкс на рівень.
  • Вибір — LinearLayout для простих рядків/колонок (до 10 елементів), ConstraintLayout для складних макетів.
  • Адаптивність — комбінація weight + 0dp + baseline alignment покриває 80% задач лінійної верстки.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також