Урок 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. Мы его уже пощупали немного на прошлом уроке. Но чтобы рассмотреть все его возможности будет отдельная статья.

Для тех, кто собрался стать Android-разработчиком

Пошаговаясхема
Пошаговая
схема

Описание процесса обучения от основ Kotlin до Android-разработчика

Бесплатныеуроки
Бесплатные
уроки

Авторский бесплатный курс по основам языка программирования Kotlin

Обучающийбот
Обучающий
бот

Тренажер и самоучитель по Котлин – бесплатные тесты и практика

Поделиться уроком

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *