ConstraintLayout представляет контейнер, который позволяет создавать гибкие и масштабируемые визуальные интерфейсы.
Для позиционирования элемента внутри ConstraintLayout необходимо указать ограничения (constraints). Есть несколько типов ограничений. В частности, для установки позиции относительно определенного элемента испльзуются следующие ограничения:
layout_constraintLeft_toLeftOf: левая граница позиционируется относительно левой границы другого элемента
layout_constraintLeft_toRightOf: левая граница позиционируется относительно правой границы другого элемента
layout_constraintRight_toLeftOf: правая граница позиционируется относительно левой границы другого элемента
layout_constraintRight_toRightOf: правая граница позиционируется относительно правой границы другого элемента
layout_constraintTop_toTopOf: верхняя граница позиционируется относительно верхней границы другого элемента
layout_constraintTop_toBottomOf: верхняя граница позиционируется относительно нижней границы другого элемента
layout_constraintBottom_toBottomOf: нижняя граница позиционируется относительно нижней границы другого элемента
layout_constraintBottom_toTopOf: нижняя граница позиционируется относительно верхней границы другого элемента
layout_constraintBaseline_toBaselineOf: базовая линия позиционируется относительно базовой линии другого элемента
layout_constraintStart_toEndOf: элемент начинается там, где завершается другой элемент
layout_constraintStart_toStartOf: элемент начинается там, где начинается другой элемент
layout_constraintEnd_toStartOf: элемент завершается там, где начинается другой элемент
layout_constraintEnd_toEndOf: элемент завершается там, где завершается другой элемент
Возможно, по поводу четырех последних свойств возникло некоторое непонимание, что подразумевается под началом или завершением элемента. Дело в том,
что некоторые языки (например, арабский или фарси) имеют правостороннюю ориентацию, то есть символы идут справа налево, а не слева направо, как в европейских языках.
И в зависимости от текущей ориентации - левосторонняя или правосторонняя - будет изменяться то, где именно начало, а где завершение элемента.
Например, при левосторонней ориентации начало - слева, а завершение - справа, поэтому атрибут layout_constraintStart_toEndOf
фактически будет аналогичен атрибуту layout_constraintLeft_toRightOf
. А при правосторонней ориентации - атрибуту
layout_constraintRight_toLeftOf
, так как начало справа, а завершение - слева
Каждое ограничение устанавливает позиционирование элемента либо по горизонтали, либо по вертикали. И для определения позиции элемента в ConstraintLayout необходимо указать как минимум одно ограничение по горизонтали и одно ограничение по вертикали.
Позиционирования может производиться относительно границ самого контейнера ContentLayout (в этом случае ограничение имеет значение parent), либо же относительно любого другого элемента внутри ConstraintLayout, тогда в качестве значения ограничения указывается id этого элемента.
Простейший пример:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" android:textSize="30sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
В данном случае у элемента TextView установлено два ограничение: одно погоризонтальной линии (app:layout_constraintLeft_toLeftOf="parent"
),
второе - по вертикальной линии (app:layout_constraintTop_toTopOf="parent"). Оба ограничения устанавливаются относительно контейнера ConstraintLayout,
поэтому они принимают значение parent, то есть ConstraintLayout.
Ограничение app:layout_constraintLeft_toLeftOf="parent"
устанавливает левую границу TextView у левой границы контейнера.
Ограничение app:layout_constraintTop_toTopOf="parent"
устанавливает верхнюю границу TextView у верхней границы контейнера.
В итоге TextView будет располагаться в верхнем левом углу контейнера.
Стоит обратить внимание, что все эти атрибуты ограничений берутся из пространства имен "http://schemas.android.com/apk/res-auto", которое проецируется на префикс app.
Если необходимо установить ограничение относительно другого элемента, то необходимо указать id этого элемента:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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"> <EditText android:id="@+id/editText" android:layout_width="180dp" android:layout_height="wrap_content" android:hint="Введите Email" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Отправить" app:layout_constraintLeft_toRightOf="@id/editText" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Здесь для текстового поля ввода EditText устанавливаются два ограничения относительно родительского контейнера ConstraintLayout, поэтому ограничения имеют значение parent, а сам EditText выравнивается по левой и верхней границе контейнера. Верхняя граница кнопки Button также выравнивается по верхней границе контейнера. А вот левая граница кнопки выравнивается по правой границе EditText. Для этого в качестве значения атрибута передается id EditText:
app:layout_constraintLeft_toRightOf="@id/editText"
Подобным образом можно составлять различные комбинации атрибутов для определения нужного нам позиционирования. Например, изменим код кнопки:
<Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Отправить" app:layout_constraintLeft_toRightOf="@id/editText" app:layout_constraintTop_toBottomOf="@id/editText" />
В данном случае верхняя граница кнопки выравнивается по нижней границе EditText
Более того мы можем позиционировать оба элемента один относительно другого:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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"> <EditText android:id="@+id/editText" android:layout_width="wrap_content" android:layout_height="wrap_content" android:hint="Введите Email" app:layout_constraintRight_toLeftOf="@+id/button" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Отправить" app:layout_constraintLeft_toRightOf="@id/editText" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Если необходимо расположить элемент в центре контейнера по вертикали, то надо использовать пару атрибутов
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"
Если необходимо расположить элемент в центре контейнера по горизонтали, то надо использовать следующую пару атрибутов
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"
Соответственно для расположения в центре контейнера по вертикали и горизонтали надо применить все выше указанные четыре атрибута:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello Android" android:textSize="30sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Если элементы расположены по центру, ConstraintLayout позволяет их сдвигать по горизонтали и по вертикали. Для сдвига по горизонтали применяется атрибут layout_constraintHorizontal_bias, а для сдвига по вертикали - атрибут layout_constraintVertical_bias. В качестве значения они принимают число с плавающей точкой от 0 до 1. Значение по умолчанию - 0.5 (расположение по центру). Например:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Top TextView" android:textSize="30sp" android:background="#e0e0e0" app:layout_constraintHorizontal_bias="0.2" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Bottom TextView" android:textSize="30sp" android:background="#e0e0e0" app:layout_constraintHorizontal_bias=".9" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintBottom_toBottomOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
Первый TextView сдвигается на 20% от левой границы контейнера (значение по умолчанию - 0.5, поэтому при значении 0.2 элемент сдвигается влево). Второй TextView сдвигается на 90% от левой границы контейнера. Например, значение 1 означало бы, что элемент придвинут к правой границе, а значение 0 - к левой
Аналогично работает атрибут layout_constraintVertical_bias, который сдвигает по вертикали.