Android XML: Расположение элементов. LinearLayout


В этом уроке мы рассмотрим базовую теорию по размещению элементов и рассмотрим LinearLayout в действии.
Layout - это контейнер, где мы располагаем свои элементы. Я могу использовать 2 обозначения как контейнер, так и Layout (лэяут)

В современной разработке под Android есть 2 основных базовых и очень важных контейнера:

  • LinearLayout - из названия понимаем, что это контейнер которой располагает в ряд. Вертикально или горизонтально.
  • ConstraintLayout  - это контейнер, который располагает элементы относительно привязок. 

И еще несколько дополнительных:

  • TableLayout - контейнер, который располагает статические элементы в таблице в зависимости от настроек - сколько колонок и строк в таблице
  • ScrollView и HorizontalScrollView - контейнеры для горизонтального и вертикального скрола 1 большого статического элемента который по размерам больше чем экран! 
  • RecyclerView / ListView / GridView - Не совсем контейнеры по своей сущности, но они созданы для размещения динамических списков которые строятся не из XML а из Java / Kotlin кода. К примеру, список чатов или сообщений в Instagram / Telegram
  • CoordinatorLayout -  Его основная задача это анимации, а не просто расположения. Все эти плавные взаимодействия, когда вы скролите контент и что-то где-то появляется или прячется сделано при помощи этого контейнера. Все взаимодействия реализовываются при помощи CoordinatorLayout.Behavior 

Чтоб понимать, как размещать элементы в контейнерах нам нужно понять, как задавать размер всех элементов.  Для того чтоб задать размер - нам надо взаимодействовать с атрибутами android:layout_width и android:layout_height который может принимать следующие значения:

  • фиксированное значения заданное в единицах dp, к примеру 100dp или 34dp или даже 570dp и так далее.
  • match_parent - указание элементу занять все доступное пространство. Именно поэтому ширина и высота (android:layout_width и android:layout_height) у корневого LinearLayout имеет значение match_parent. То есть сделать ширину и высоту такой, какой есть размер всего экрана на устройстве.
  • wrap_content - указание элементу занять ровно столько пространства, сколько нужно контенту + внутреннему паддингу, ну или в случае последним элементом - столько, сколько осталось у контейнера, в котором находится элемент. Что мы и видим на скриншоте выше - кнопки имеет в себе текст + немного пространства. Который можно убрать, добавив атрибут android:padding="0dp". Именно это мы и делали в предыдущем уроке.

И так давайте рассматривать по порядку. В нашем созданном приложении внутри activity_main.xml мы видел, что у нас есть корневой тег ConstraintLayout внутри которого уже расположен наш TextView / Button. Модифицируем наш activity_main.xml следующим образом чтоб у нас был корневой элемент LinearLayout и вложенные элементы имели фиксированный размер. Давайте нашим кнопкам зададим значения - ширину - 75dp высоту 50dp соответственно задав атрибуты android:layout_width="75dp" и android:layout_height="150dp"

Пример кода:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:layout_width="75dp"
        android:layout_height="150dp"
        android:text="Start Develop" />
    <Button
        android:layout_width="75dp"
        android:layout_height="150dp"
        android:text="Start Develop" />
    <Button
        android:layout_width="75dp"
        android:layout_height="150dp"
        android:text="Start Develop" />

    <Button
        android:layout_width="75dp"
        android:layout_height="150dp"
        android:text="Start Develop" />

</LinearLayout>

Получившийся результат:

Android XML: Расположение элементов. LinearLayout

 

Выглядит не красиво. Но в этом моменте нам главное понять, как работает настройка размера для всех View. 
Можете попробовать задать разный размер кнопкам. К примеру, значения от 100 до 300 dp и посмотрите, как оно будет меняться.
 

А что будет если мы зададим размер как wrap_content для всех кнопок - попросим кнопки занять столько места, сколько им необходимо для текста:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Develop" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Develop" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Develop" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Start Develop" />

</LinearLayout>

Мы увидим следующий результат.

Android XML: Расположение элементов. LinearLayout

 

По умолчанию LinearLayout располагает элементы горизонтально и да - последний элемент не вместился на экране.
LinearLayout умеет обрабатывать такие вещи, но ценой изменения размера у внутренних элементов.  Для этого нам нужно задать атрибут android:layout_weight="1" для наших Button. Тут надо понимать, что главное не значение в атрибуте, а значения во всех элементах. То есть если все элементы будут иметь android:layout_weight="1" то LinearLayout даст всем элементам одинаковый размер. Ну соответственно если давать значения разные, то LinearLayout будет высчитывать кому какой размер дать.

И так добавляем каждому элементу атрибут android:layout_weight="1"  и видим следующий результат:

Android XML: Расположение элементов. LinearLayout

 

LinearLayout посчитал ширину для каждого элемента и задал ее. Но текст внутри кнопке не влез. Следовательно, появился перенос на новую строку и как результат высота увеличилась до нужной чтоб влез контент + padding поскольку она задана как wrap_content - столько, сколько нужно контенту. 

ВАЖНО! Тут есть нюанс - атрибут android:layout_weight работает в ту сторону (ширину или высоту) куда располагает элементы LinearLayout. Выше было сказано что по умолчанию LinearLayout располагает элементы горизонтально. Именно поэтому ширина для кнопок была посчитана контейнером! А высота кнопок была посчитана самой кнопкой!

Давайте попросим LinearLayout расположить элементы вертикально оставив layout_weight для элементов и просто добавим атрибут android:orientation="vertical" для нашего LinearLayout

И вот его результат:

Android XML: Расположение элементов. LinearLayout

 

Как было описано выше - LinearLayout посчитал и задал высоту для каждой кнопки. То есть атрибут android:layout_width="wrap_content" для высоты был проигнорирован и переписан. Поскольку у всех кнопок значение weight одинаково - то все кнопки имеют одинаковую высоту чтоб заполнить весь экран.


Нужна помощь? Спросите в нашем Телеграмм канале - Start-Develop RU / Start-Develop EN