Урок 3: Контейнеры — FrameLayout, LinarLayout. Отступы

Урок 3: Контейнеры — FrameLayout, LinarLayout. Отступы

Вложенность элементов в XML

Итак, как вы уже поняли, XML – это язык разметки, который среди прочего позволяет задать вложенность элементов относительно друг друга. А атрибуты определяют свойства и характеристики элементов разметки. Элементами являются View. Вообще в целом интерфейс в Android приложениях – это набор вложенных друг в друга компонентов.

Забегая немного вперед, слишком глубокая вложенность плохо влияет на производительность. То есть системе приходится тратить больше ресурсов на высчитывание размеров элементов исходя из параметров экрана и размеров друг относительно друга. Если мы верстаем, используя Compose, то это не очень актуально. Но для XML нужно стараться создавать как можно меньше вложенных слоев.

На этом уроке рассмотрим какие еще бывают лэйауты (или контейнеры) и какими свойствами они обладают.

Что такое контейнер?

“Вьюхи” (Views) делятся на 2 большие группы. Это view, которые непосредственно отрисовываются и view, которые содержат в себе другие view. То есть “вьюхи”-контейнеры. Контейнеры отвечают за позиционирование, позволяют расставлять нам элементы на экране каким-угодно сложным образом.

На самом деле можно открыть палитру и посмотреть какие элементы нам доступны. Нас интересуют лейауты.

Лейауты в палитре элементов

Из палитры можно перетаскивать элементы прямо в превью, двигать их, менять размер и так далее. Но я не рекомендую так делать, потому что в таком случае верстка выходит из под контроля. У нас непредсказуемо появляются нужные/не нужные атрибуты, захардкоженные значения и так далее. Все это негативно может повлиять на адаптивность верстки. По сути в превью можно практически безболезненно двигать только стрелки для ConstraintLayout. Но и при этом обращайте внимание, что происходит в коде, не добавилось ли дополнительных значений из-за случайного сдвига элемента.

Основные лейауты

Пройдемся по основным. FrameLayout, LinearLayout и ConstraintLayout. Причем исторически был еще RelativeLayout, который вы можете встретить в старых проектах, но он сейчас не рекомендуется к использованию. Его можно найти в разделе Legacy. Этот лейаут пометили как Deprecated как раз потому, что он не очень эффективно рисует вложенные элементы. Вообще все, что вы встретите с пометкой Legacy не рекомендуется использовать.

Раздел Legacy

FrameLayout

Этот тип лейаута является наиболее простым и незамысловатым. Это некоторый стек, в который можно складывать все наши вью. Рекомендую подробнее почитать про термин стек, в будущем он вам еще пригодится. Можете думать о нем как о стопке карт — вьюхи находящиеся внутри накладываются друг на друга. И в таком же порядке считываются.

Заменю основной контейнер из прошлого урока на FrameLayout и удалю у вложенных элементов атрибуты привязки – нигде, кроме как в Constraint’е они ни на что не влияют.

Добавлю три кнопки для демонстрации. Если убрать все отступы увидим, что кнопки наложились друг на друга и самая верхняя кнопка та, которую мы разместили последней. Так и работает стек. Кроме того можно открыть вкладку ComponentTree, в которой будут расположены все элементы макета в порядке вложенности.

ComponentTree - расположение элементов макета

Так работает FrameLayout. И прежде чем продолжить давайте задержимся на теме отступов.

Отступы

Практически у всех элементов есть есть два основных атрибута для обозначения отступов. Margin и Padding.

  • Margin – внешний отступ за пределами границ View.
  • Padding – внутренний отступ внутри границ View.

Допустим, мы хотим, чтобы кнопка не прилипала к границам экрана. Что можно предпринять? Первым делом приходят на ум два варианта:

  • Добавить внутренние отступы у контейнера.
  • Добавить внешние отступы у элемента.

Реализуем и то, и то. Добавляем внутренний отступ (паддинг) для нашего контейнера в 20dp – android:padding=»20dp».

Отступы Margin и Padding

Видим, что кнопки отъехали согласно плану. Причем если не уточнять с какой конкретной стороны, то отступы добавляются сразу по всем граням. Однако, можно добавить принудительно на конкретной стороне: Start, Top, End, Bottom.

Обратите внимание, если вы вместо Start пропишите Left, всплывет предупреждение. О том, что могут возникнуть проблемы при поддержке языков с правого на левый направлением чтения (RTL). Сразу привыкайте обозначать начало и конец элемента правильно — через start и end.

Теперь добавим у первого элемента кнопки внешний и внутренний отступы, например, 100dp – android:layout_margin="100dp" и 30dp android:padding="30dp". Теперь мы видим, как изменилось положение на 100 пунктов внутрь контейнера и кнопка увеличилась на 30 пунктов за счет добавления отступа внутри View.

Добавление внешнего и внутреннего отступа
Разница между gravity и layout_gravity

Хорошо. На прошлом уроке я обещал рассказать про разницу атрибутов gravity и layout_gravity. Этот атрибут отвечает за позиционирование элементов в пространстве. Нужно запомнить простое правило.

  • Атрибуты, которые начинаются со слова layout влияют не на саму “вью”, а на родителя — то есть на ту “вью”, в которой они находятся.
  • Атрибуты, которые не начинаются со слова layout распространяются непосредственно на ту “вью”, в которой этот атрибут прописан.

Чтобы продемонстрировать это, я применю layout_gravity к первой кнопке. Прописав android:layout_gravity=»end», кнопка будет занимать место в правой части контейнера.

Применение layout_gravity к первой кнопке

Уберу отступы, чтобы они пока что не вводили в заблуждение. Без margin и padding у контейнера кнопка совсем приклеится к его правой стороне. Контейнер, замечу, по умолчанию занимает весь экран. Таким образом layout_gravity повлиял на родителя, то есть на внешний контейнер и он (контейнер) разместил этот элемент внутри себя у правой грани.

Влияние layout_gravity на размещение элемента

Можно одновременно задавать позиционирование по горизонтали и по вертикали. Для этого нужно разделить значения атрибутов вертикальной чертой: android:layout_gravity=»end|center». Причем еще можно уточнить по какой оси выполнить центрирование — по горизонтали или по вертикали.

Центрирование элемента layout_gravity=end|center

Окей. Теперь я пропишу атрибут gravity, чтобы повлиять на расположение текста внутри кнопки — android:gravity=»bottom». Теперь текст прижмется к нижней части кнопки, а чтобы это было более наглядно увеличу ее размеры.

Расположение текста внутри кнопки с помощью атрибута gravity

Нужно понимать, что не все контейнеры работают со всеми подряд атрибутами, например не на все контейнеры подействует свойство потомка layout_gravity. На FrameLayout это действие распространяется.

LinearLayout

Далее. LinearLayout – это компонент, который позволяет расставлять потомков внутри себя в ряд горизонтально или вертикально. “Вьюшки” уже не накладываются друг на друга. Давайте я изменю наш контейнер Frame на Linear.

Изменение контейнера изменю наш контейнер Frame на Linear

По-умолчанию в этом контейнере ориентация горизонтальная. Поэтому элементы выстраиваются в горизонтальную последовательность. Обратите внимание, что все кнопки расположены слева направо в порядке их добавления на макет. Первая кнопка с вертикальным центрированием. Добавим атрибут для того, чтобы элементы выстроились друг под другом – android:orientation=»vertical».

Добавление атрибута orientation=vertical

У вложенных в LinearLayout элементов есть атрибут layout_weight, через который можно указать уникальный вес и они будут автоматически делить пространство между собой. Вот так убрав лишние атрибуты с размерами и центрированием кнопки заполнили все свободное пространство контейнера по вертикали.

Атрибут layout_weight

Смотрите, сейчас сумма указанных весов 3, но у этого контейнера есть еще один кастомный атрибут, который позволяет принудительно указать сумму весов. Без его указания сумма считается автоматически. Если указать сумму весов с помощью атрибута android:weightSum=»4″. Увидим, что размер элементов пересчитался и свободное место осталось под значение веса 1. Атрибут суммы весов используется реже, в отличие от установки веса для каждого элемента в отдельности. Можно поиграться со значениями и подобрать нужное соотношение под ваши задачи.

weightSum=4 атрибут, указывающий сумму весов

Надо добавить, что не запрещено создавать вложенные один в другой контейнеры. Все зависит от бизнес задачи и подходе к ее выполнению. Простой пример вложенности контейнеров можно представить. Когда у вас есть один LinearLayout с вертикальной ориентацией. И внутри него вы создаете несколько контейнеров с горизонтальной ориентацией. Располагая в них различные View типа текста, кнопок и так далее. Сейчас демонстрировать не буду, но при верстке макетов на этих уроках и в рамках практикума по Android будет много демонстрации и самостоятельной работы.

Остался еще самый продвинутый на сегодняшний день лейаут — ConstraintLayout. Мы его уже пощупали немного на прошлом уроке. Но чтобы рассмотреть все его возможности будет отдельная статья.

Бесплатные Telegram-боты для обучения

Практика с проверкой кода и помощью ИИ-ментора

AndroidSprint AI Mentor

Проверяет Pull Request'ы в GitHub, проводит тестовые собеседования с голосом и таймером, помогает разбираться с кодом 24/7

Попробовать ИИ-ментора →

KotlinSprint Bot

22 урока Kotlin, 220 тестов, 120 практических задач с код-ревью

Начать обучение Kotlin →

AndroidSprint Bot

Тесты по Android SDK, Jetpack Compose, архитектуре приложений

Тесты по Android →

Тебе также может быть интересно

Узнать подробнее
Курс AndroidSprint

Глубокое обучение Android разработке с 0 до получения оффера. Только персональная практика с гарантией получения продуктового опыта.

Курс AndroidSprint - Глубокое <strong>обучение Android разработке с 0 до получения оффера</strong>. Только персональная практика с гарантией получения продуктового опыта.
Узнать подробнее
Узнать подробнее
Практикум по Kotlin

Изучение Котлин с 0 для профессиональной разработки. Личный ментор и разбор кода задач через git-flow.

Практикум по Kotlin - Изучение Котлин <strong>с 0 для профессиональной разработки</strong>. Личный ментор и разбор кода задач через git-flow.
Узнать подробнее
Узнать подробнее
Бесплатные уроки по Kotlin разработке

Самостоятельное освоение базы по языку для дальнейшего развития в Android/back-end разработке или в автотестах.

Бесплатные уроки по Kotlin разработке - <span>Самостоятельное освоение базы по языку для дальнейшего развития в Android/back-end разработке или в автотестах.</span>
Узнать подробнее
Узнать подробнее
Onboarding в разработку

Полное обучение Android разработке с нуля до получения оффера. Делаем упор на практику и обратную связь

Onboarding в разработку - <span>Полное обучение Android разработке с нуля до получения оффера. Делаем упор на практику и обратную связь</span>
Узнать подробнее
Узнать подробнее
Обучающий Kotlin телеграм бот (с тестами)

Ваш основной инструмент для изучения основ языка. Бесплатные тесты и практика внутри.

Обучающий Kotlin телеграм бот (с тестами) - Ваш основной <span>инструмент для изучения основ языка.</span> Бесплатные тесты и практика внутри.
Узнать подробнее
Узнать подробнее
Бесплатные уроки по Android разработке

Самостоятельное обучение разработке Андроид приложений. Понятные видеоуроки с разжеванными примерами.

Бесплатные уроки  по Android разработке - Самостоятельное <span>обучение разработке Андроид приложений.</span> Понятные видеоуроки с разжеванными примерами.
Узнать подробнее
Узнать подробнее
Курс по UI/Unit тестированию

Для ручных тестировщиков, которые готовы осваивать автотесты с использованием актуального стека технологий. [в разработке]

Курс по UI/Unit тестированию - Для ручных тестировщиков, которые <span>готовы осваивать автотесты</span> с использованием актуального стека технологий. [в разработке]
Узнать подробнее
Узнать подробнее
Обучающий Android телеграм бот (с тестами)

Бесплатные теоретические тесты для самопроверки. А также информер на практических спринтах по Android.

Обучающий Android телеграм бот (с тестами) - Бесплатные <span>теоретические тесты для самопроверки.</span> А также информер на практических спринтах по Android.
Узнать подробнее