Рассказываем суть RelativeLayout — ViewGroup в Android SDK для позиционирования дочерних элементов относительно друг друга или относительно родительского контейнера. В отличие от LinearLayout, который выстраивает элементы строго последовательно, RelativeLayout позволяет расположить любой элемент слева, справа, выше, ниже или по центру относительно любого другого элемента по его ID. Это делает RelativeLayout удобным для перекрывающихся и сложных макетов без вложенности. Основные правила описаны в документации Android Developers.
Главное
RelativeLayout — ViewGroup, появившаяся в Android SDK начиная с API Level 1, которая позиционирует дочерние элементы через декларативные правила (layout rules) относительно родителя или других дочерних элементов. Каждое правило задаётся XML-атрибутом вида android:layout_above, android:layout_below, android:layout_toLeftOf со значением ID целевого элемента.
До появления RelativeLayout разработчики были вынуждены использовать вложенные LinearLayout для каждого нестандартного позиционирования — это приводило к глубокой вложенности и медленной отрисовке. RelativeLayout решил эту проблему, предложив относительное позиционирование на одном уровне иерархии. Однако его гибкость ограничена по сравнению с современным ConstraintLayout: RelativeLayout не поддерживает цепи, барьеры, направляющие и процентные размеры.
RelativeLayout имеет две ключевые особенности: один проход onMeasure (в отличие от LinearLayout с weight, требующим два прохода) и зависимость от порядка объявления — если элемент A ссылается на элемент B, а B объявлен после A, B должен иметь известный размер на момент измерения A. По данным Android Developers Guide (2024), RelativeLayout выполняет измерение за один проход, если все правила ссылаются на уже измеренные элементы. В противном случае требуется второй проход, что снижает производительность.
RelativeLayout оправдан для простых макетов с 3–7 элементами, где требуется относительное позиционирование (надпись над кнопкой, иконка справа от текста, панель внизу экрана). Для новых проектов рекомендуется ConstraintLayout, но RelativeLayout всё ещё широко используется в legacy-коде и библиотеках.
RelativeLayout использует два типа правил: relative-правила (позиционирование относительно другого элемента) и align-правила (привязка к родителю). Каждый дочерний элемент может иметь неограниченное количество правил, но конфликтующие правила (например, alignParentTop и below другого элемента) разрешаются в пользу последнего объявленного в атрибуте.
Relative-правила:
- android:layout_above="@id/target" — нижняя граница элемента привязана к верхней границе target.
- android:layout_below="@id/target" — верхняя граница элемента привязана к нижней границе target.
- android:layout_toLeftOf="@id/target" — правая граница привязана к левой границе target.
- android:layout_toRightOf="@id/target" — левая граница привязана к правой границе target.
- android:layout_toStartOf="@id/target" — аналог toLeftOf для RTL-локализаций.
- android:layout_toEndOf="@id/target" — аналог toRightOf для RTL.
Align-правила (к родителю):
- android:layout_alignParentTop="true" — верхний край элемента совпадает с верхним краем родителя.
- android:layout_alignParentBottom="true" — нижний край совпадает с нижним краем родителя.
- android:layout_alignParentLeft="true" — левый край совпадает с левым краем родителя.
- android:layout_alignParentRight="true" — правый край совпадает с правым краем родителя.
- android:layout_alignParentStart и android:layout_alignParentEnd — для RTL.
Align-правила к другим элементам:
- android:layout_alignTop="@id/target" — верх элемента совпадает с верхом target.
- android:layout_alignBottom, android:layout_alignLeft, android:layout_alignRight, android:layout_alignStart, android:layout_alignEnd — аналогично.
- android:layout_alignBaseline="@id/target" — выравнивание по базовой линии текста (полезно для строк с разными размерами шрифта).
Центрирование в RelativeLayout задаётся тремя атрибутами: android:layout_centerInParent="true" (по центру родителя по обеим осям), android:layout_centerHorizontal="true" (по центру по горизонтали) и android:layout_centerVertical="true" (по центру по вертикали). Центрирование совместимо с другими правилами: элемент может быть центрирован по горизонтали и при этом привязан к нижнему краю родителя.
Порядок наложения (Z-order) в RelativeLayout определяется порядком объявления элементов в XML. Первый объявленный элемент рисуется первым (будет ниже), последний — последним (будет выше). Если нужно изменить порядок наложения без изменения XML, используйте android: elevation (начиная с API 21) — элементы с большей elevation рисуются поверх. Для версий ниже API 21 порядок наложения регулируется только порядком объявления.
Важно: RelativeLayout не поддерживает атрибут android:elevation для родителя — каждый элемент управляет своей elevation самостоятельно. При конфликте правил позиционирования и elevation (например, перекрывающиеся элементы) elevation имеет приоритет для отрисовки, но не для позиционирования — элемент с большей elevation может визуально перекрывать другой, даже если его layout-правила ставят его «позади».
Аватар по центру вверху, имя под аватаром, статус под именем, кнопка действия внизу экрана. Все элементы используют relative-правила для последовательной привязки.
<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="Иван Иванов"
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="Онлайн"
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="Редактировать профиль" />
</RelativeLayout>
Аватар привязан к верху через marginTop + centerHorizontal, имя — под аватаром через layout_below, статус — под именем, кнопка — к нижнему краю родителя через alignParentBottom. Все элементы независимы друг от друга, нет цепочек и вложенности.
Иконка с красным бейджем (кружок с числом) в правом верхнем углу. Бейдж позиционируется относительно иконки через align к её краям с минусовыми margin для наложения.
<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>
Бейдж привязан к верхнему и правому краю иконки. Отрицательные margin (-6dp) сдвигают бейдж наружу, создавая эффект перекрытия границы иконки. Это популярный паттерн для уведомлений, который без RelativeLayout потребовал бы FrameLayout или кастомной отрисовки.
Форма логина: логотип по центру вверху, поле email под ним, поле пароля под email, кнопка «Войти» под паролем, ссылка «Регистрация» прижата к низу. Все элементы привязаны последовательно через 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="Пароль"
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="Войти" />
<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="Нет аккаунта? Зарегистрироваться"
android:textColor="@color/primary" />
</RelativeLayout>
Экран использует 5 элементов на одном уровне иерархии. Поток сверху вниз (logo → email → password → button) обеспечивается через layout_below, а ссылка прижата к низу через alignParentBottom. Для той же функциональности LinearLayout потребовал бы два вложенных контейнера (один для верхней группы, второй для ссылки с weight).
Сравнение двух ViewGroup для относительного позиционирования: RelativeLayout (классическая, API 1+) и ConstraintLayout (современная, Jetpack). Критерии: гибкость, производительность, RTL-поддержка и адаптивность.
| Характеристика | RelativeLayout | ConstraintLayout |
|---|---|---|
| Процентные размеры | Нет (только фиксированные и match_parent) | Да (width_percent, height_percent, guideline_percent) |
| RTL-поддержка | Через start/end (API 17+) | Встроенная |
| Chain / цепочки | Нет | Да (spread, spread_inside, packed) |
| Barrier / Group / Flow | Нет | Да (виртуальные помощники) |
| MotionLayout анимации | Нет | Да |
| Проходы onMeasure | 1 (без циклов зависимостей) | 2 (всегда, но оптимизированные) |
| Центрирование | centerInParent, centerHorizontal, centerVertical | Через bias (0.0–1.0) с противоположными констрейнтами |
| Когда использовать | Legacy-код, простые макеты с 3–7 элементами | Новые проекты, сложные экраны, адаптивные макеты |
RelativeLayout уступает ConstraintLayout практически по всем параметрам, кроме одного: он встроен в Android SDK с API 1 и не требует дополнительных зависимостей. Для проектов, которые всё ещё используют minSdk ниже API 14 (Android 4.0), RelativeLayout — единственный стандартный вариант относительного позиционирования. Во всех остальных случаях Google рекомендует ConstraintLayout.
Часто задаваемые вопросы
Самая вероятная причина — отсутствие достаточного количества правил позиционирования. Каждый элемент в RelativeLayout должен иметь хотя бы одно правило по горизонтали (alignParentLeft, toRightOf, centerHorizontal) и одно по вертикали (alignParentTop, below, centerVertical). Если правил нет, элемент оказывается в позиции (0,0) и может быть скрыт под другими элементами или за пределами экрана. Вторая причина — циклическая зависимость (элемент A привязан к B, B привязан к A), которая приводит к непредсказуемому поведению.
Используйте атрибут android:layout_centerInParent="true". Он центрирует элемент по обеим осям одновременно. Если нужно только по горизонтали — android:layout_centerHorizontal="true", только по вертикали — android:layout_centerVertical="true". Центрирование работает в сочетании с margin — элемент будет смещён относительно центра на указанный отступ.
Можно, но не рекомендуется. RelativeLayout выполняет два прохода onMeasure при наличии циклических зависимостей, что на 15–30% медленнее ConstraintLayout в списках RecyclerView. Для item-макетов RecyclerView используйте ConstraintLayout — он обеспечивает плоскую иерархию с минимальным временем измерения. Если RelativeLayout уже используется в legacy-проекте, убедитесь, что элементы не создают циклических зависимостей, и измерьте FPS скролла через Profile GPU Rendering.
android:layout_margin задаёт отступы со всех сторон одновременно. android:layout_marginTop — только сверху. Приоритет у более специфичного атрибута: если задан и layout_margin (16dp), и layout_marginTop (8dp), верхний отступ будет 8dp. В RelativeLayout margin работает относительно констрейнта, а не относительно соседнего элемента: layout_marginTop при layout_below="@id/target" — это отступ от верхней границы элемента до нижней границы target.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также