Урок 2. Работа с RelativeLayout на примере UserInfoScreen

Код начала урока:

gitzip

Структура урока:

Видео версия урока

Изменение activity_user_info, используя RelativeLayout.

В прошлом уроке мы с вами сделали экран отображения данных пользователя, используя контейнер (ViewGroup) LinearLayout. В этом уроке мы создадим этот экран заново, используя RelativeLayout.

Исходя из названия, RelativeLayout (рус. относительный макет или если перефразировать – макет с относительным расположением элементов) может располагать элементы относительно друг друга. У его вложенных элементов есть ряд параметров для указания зависимостей относительно остальных элементов или же самого RelativeLayout.

Элементы внутри RelativeLayout имеют свойства отвечающие за их расположение по вертикали и горизонтали. По умолчанию горизонтальное свойство расположения прижато к левому краю RelativeLayout, а вертикальное к верхнему. Получается по умолчанию расположение элементов зависят от верхнего и левого края родительского контейнера RelativeLayout. Часто такое зависящее от чего-то расположение для удобства называют зависимостью. Например, установить для текста зависимость снизу от кнопки и справа от родительского контейнера. Если вы не укажете ни одной зависимости, то все элементы будут располагаться один над одним в верхнем левом углу. Причём элемент, который будет ниже всего в xml файле будет находиться поверх остальных.

Давайте изменим структуру нашего activity_user_info.xml файла. Заменим корневой элемент на RelativeLayout (удалив свойство android:orientation="vertical" потому что оно не применяется к RelativeLayout) и вставим версию нашего layout, когда все элементы лежат на одном уровне (без вложенного контейнера LinearLayout) :

activity_user_info.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp">

    <ImageView
        android:id="@+id/user_image_view"
        android:src="@mipmap/ic_launcher"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/user_name_text_view"
        android:text="Имя"
        android:layout_marginTop="5dp"
        android:textSize="16sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/user_nick_text_view"
        android:text="Ник"
        android:layout_marginTop="5dp"
        android:textSize="16sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/user_description_text_view"
        android:text="Описание"
        android:layout_marginTop="5dp"
        android:textSize="16sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/user_location_text_view"
        android:text="Местоположение"
        android:layout_marginTop="5dp"
        android:textSize="16sp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <TextView
        android:id="@+id/following_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="Читает"
        android:textSize="16sp"/>

    <TextView
        android:id="@+id/followers_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="5dp"
        android:text="Читатели"
        android:textSize="16sp"/>

</RelativeLayout>

Смотрим, как он выглядит на вкладке Design:

UserInfoLayoutOverlapped.png

Теперь нам необходимо исправить эту ситуацию. В левом верхнем углу должен остаться user_image_view, а user_name_text_view должен находиться под ним. Для этого применим свойство android:layout_below="@id/user_image_view". Оно делает именно то, что нам надо. У RelativeLayout есть такие же свойства только для других направлений:

  • android:layout_below – находиться под элементом.
  • android:layout_above – находиться над элементом.
  • android:layout_toStartOf – находиться слева(в начале) от элемента.
  • android:layout_toEndOf – находиться справа (в конце) от элемента

Сейчас нам достаточно добавить зависимость android:layout_below для каждого нижестоящего элемента:

activity_user_info.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp">

    <ImageView
        android:id="@+id/user_image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/ic_launcher"/>

    <TextView
        android:id="@+id/user_name_text_view"
        android:layout_below="@id/user_image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="Имя"
        android:textSize="16sp"/>

    <TextView
        android:id="@+id/user_nick_text_view"
        android:layout_below="@id/user_name_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="Ник"
        android:textSize="16sp"/>

    <TextView
        android:id="@+id/user_description_text_view"
        android:layout_below="@id/user_nick_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="Описание"
        android:textSize="16sp"/>

    <TextView
        android:id="@+id/user_location_text_view"
        android:text="Местоположение"
        android:layout_below="@id/user_description_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:textSize="16sp"/>

    <TextView
        android:id="@+id/following_text_view"
        android:layout_below="@id/user_location_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="Читает"
        android:textSize="16sp"/>

    <TextView
        android:id="@+id/followers_text_view"
        android:layout_below="@id/following_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="5dp"
        android:text="Читатели"
        android:textSize="16sp"/>

</RelativeLayout>

В результате видим:

UserInfoLayoutBelow.png

Выглядит уже лучше, но последний элемент(followers_text_view) должен находиться не под following_text_view, а справа от него. Мы хотим, чтобы наш элемент находился снизу от user_location_text_view и справа от following_text_view. Добавим атрибуты android:layout_below="@id/user_location_text_view" и android:layout_toEndOf="@+id/following_text_view" к элементу followers_text_view.

activity_user_info.xml

<RelativeLayout>

    <!--Остальные элементы сверху не изменились -->

    <TextView
        android:id="@+id/followers_text_view"
        android:layout_below="@id/user_location_text_view"
        android:layout_toEndOf="@+id/following_text_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="5dp"
        android:text="Читатели"
        android:textSize="16sp"/>
</RelativeLayout>

После этого видим, что мы получили такой же layout, как в предыдущем уроке:

UserInfoLayoutReady.png

Какие преимущества от того, что мы используем RelativeLayout? Мы убрали вложенный контейнер LinearLayout. В данном примере это было не критично, но вообще важно помнить, что слишком глубокая вложенность приводит к снижению производительности пользовательского интерфейса. Хорошей практикой является вложенность не больше 10 уровней.

Осталась ещё одна вещь, которую надо помнить, когда используете RelativeLayout. Нельзя объявлять круговые (транзитивные) зависимости. Т.е. если мы зададим кнопке свойство android:layout_toStartOf="@+id/search_edit_text", а к EditText добавим зависимость android:layout_toStartOf="@+id/search_button", то приложение выдаст исключение java.lang.IllegalStateException: Circular dependencies cannot exist in RelativeLayout. Можете проверить это, если не верите :)

Подведём итоги:

  • RelativeLayout позволяет элементам указывать зависимости как относительно друг друга, так и относительно сторон самого родительского контейнера RelativeLayout.
  • Его нужно использовать, когда мы видим не линейную структуру элементов.
  • RelativeLayout позволяет избавиться от вложенности контейнеров в отличие от LinearLayout

Полезные материалы:

Полный листинг изменений кода:

Code diff

УВИДЕТЬ ВСЕ Добавить заметку
ВЫ
Добавить ваш комментарий