Как задать относительные позиции виджетам в ConstraintLayout

pavlofff

В ConstraintLayout требуется задать относительное позиционирование вложенных виджетов.

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

1 ответ

pavlofff

Верстать данную разметку будем в режиме визуального редактора, так как это нам сильно упростит жизнь в данном случае из-за довольно длинных имен атрибутов, которые использует данный контейнер.

Также можно почитать обзорную статью по основным моментам работы с новым визуальным редактором, чтобы изложенное лучше воспринималось.

Начинаем работу с того, что задаем две опорные линии. Для этого кликаем правой кнопкой мыши по области редактирования и выбираем Add Vertical Guidline для вертикальной и Add Horizontal Guidline для горизонтальной:

UPD: C Android Studio 2.2 Preview3 опорные линии можно задать из панели инструментов вверху редактора:

Отключаем автоматическое связывание виджетов (подковка вверх с синими концами, в левом верхнем углу, должна быть зачеркнута), так как эта функция не всегда хорошо понимает, что хочет человек.

По умолчанию опорная линия позиционируется по относительным координатам (расстоянию в dp), о чем сообщает изображение стрелочки в кружочке этой линии. Но нам нужно относительное позиционирование в процентах, поэтому кликаем мышкой на эту стрелочку в кружочке и она приобретает вид с процентами - двигаем за этот кружочек в нужные позиции: вертикальную устанавливаем в 50%, а горизонтальную устанавливаем в 34% (треть экрана), затем бросаем на разметку три виджета, которые нам нужны (ImageView и две Button):

Теперь привязываем к этим линиям наши виджеты, кликаем на виджет и соединяем кружочки на их гранях с привязочными линиями: кнопки - левую кнопку с левого края с краем экрана и нижнюю точку с низом экрана, правый кружок с вертикальной опорной линией, правую кнопку так же, только в зеркально (UPD С версии 1.0 появился режим компоновки chains (цепочки), который позволяет обойтись без вертикальной опорной линии):

Размер кнопкам по горизонтали назначаем - максимальное расстояние (аналог match_parent), в квадрате справа щелкаем по горизонтальным линиям, пока не появится в виде "пилы" - . (треугольнички - wrap_content, отрезок - фиксированный размер). Вертикальный оставляем, как есть (в виде треугольничков - wrap_content). Задаем маржины, числа сбоку от пиктограмм размера виджета (здесь 16dp и 8dp).

С кнопками все.

Теперь нижний край (кружок снизу) у ImageView соединяем с горизонтальной опорной линией. Прочие края соединяем с краями экрана:

ставим маржины у ImageView в 0, размер виджета wrap_content:

Вот и все. Описание получилось очень длинным, но в реальности эта верстка заняла меньше минуты. В итоге получаем следующее:

Данная разметка будет сохранять свой относительный вид на любых размерах экранов с любой плотностью.

Так же следует заметить, что ConstraintLayout предпочтительнее RelativeLayout, так как гораздо лучше оптимизирован и рассчитывается быстрее, кроме того имеет больше возможностей по позиционированию. Например, в данной разметке пришлось бы вообще использовать несколько вложенных "классических" контейнеров.

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

Google сделал анимированную презентацию нового инструмента, посмотрев которую, можно освоить основные моменты работы.

в xml-виде все это выглядит следующим образом:

<android.support.constraint.constraintlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/constraintLayout">

    <android.support.constraint.guideline android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/guideline" android:orientation="vertical" app:relativepercent="50">

    <android.support.constraint.guideline android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/guideline2" android:orientation="horizontal" app:relativepercent="34">

    <button android:text="Button" android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/button" app:layout_constraintleft_toleftof="@+id/guideline" android:layout_marginleft="8dp" app:layout_constraintright_torightof="@+id/constraintLayout" android:layout_marginright="16dp" app:layout_constraintbottom_tobottomof="@+id/constraintLayout" android:layout_marginbottom="16dp">

    </button><button android:text="Button" android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/button2" app:layout_constraintleft_toleftof="@+id/constraintLayout" android:layout_marginleft="16dp" app:layout_constraintright_toleftof="@+id/guideline" android:layout_marginright="8dp" app:layout_constraintbottom_tobottomof="@+id/constraintLayout" android:layout_marginbottom="16dp">

    </button></android.support.constraint.guideline></android.support.constraint.guideline></android.support.constraint.constraintlayout>

licensed under cc by-sa 3.0 with attribution.