Розміри елементів у ConstraintLayout

У ConstraintLayout застосовуються три способи встановлення розмірів:

  • Встановлення точних розмірів, наприклад, 123dp
  • Значення WRAP_CONTENT, яке задає для віджета розміри, достатні для розташування його вмісту
  • Значення 0dp, яке еквівалентне значенню "MATCH_CONSTRAINT" у коді Java. У цьому разі розміри елемента встановлюються виходячи із зазначених для нього обмежень. За замовчуванням елемент займає весь доступний простір.

Застосуємо всі три типи встановлення розмірів:

<?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="160dp"
        android:layout_height="wrap_content"
        android:text="Top TextView"
        android:textSize="30sp"
        android:background="#e0e0e0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
 
    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Center TextView"
        android:textSize="30sp"
        android:background="#e0e0e0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
 
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Bottom TextView"
        android:textSize="30sp"
        android:background="#e0e0e0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
 
</androidx.constraintlayout.widget.ConstraintLayout>

Тут створюються три елементи TextView. Усі вони центруються по горизонталі, але по вертикалі розташовуються по верхній і нижній межі контейнера і в центрі. Для всіх трьох TextView для висоти задано значення wrap_content, тобто всі три елементи займатимуть ту висоту, яка для них є кращою, щоб вмістити вміст:

android:layout_height="wrap_content"

Однак для кожного елемента задано свої налаштування ширини. Для верхнього TextView встановлено точні розміри - 160 одиниць:

android:layout_width="160dp"

Для центрального TextView встановлено значення "0dp", завдяки чому елемент за замовчуванням займатиме весь доступний для нього простір (у цьому разі розтягуватиметься по горизонталі):

android:layout_width="0dp"

Для нижнього TextView встановлено значення "wrap_content", тобто елемент прийматиме ту ширину, яка необхідна для вміщення його вмісту:

android:layout_width="wrap_content"

Варто зазначити, що у вкладених віджетах у ConstraintLayout не рекомендується використовувати значення match_parent, яке дає змогу віджету зайняти весь доступний простір. Замість цього рекомендується використовувати 0dp або "MATCH_CONSTRAINT" - разом з іншими обмеженнями вони дадуть необхідний ефект. Так, для розтягування по ширині контейнера застосовуються такі атрибути:

android:layout_width="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"

А для розтягування по висоті контейнера застосовуються такі атрибути:

android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"

Наприклад, розтягнення TextView по всій довжині та ширині контейнера:

<TextView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:text="Hello Android"
    android:textSize="30sp"
    android:background="#e0e0e0"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"/>

Мінімальні та максимальні розміри

Низка атрибутів задають максимальні та мінімальні розміри:

  • layout_constraintWidth_min і layout_constraintHeight_min: представляють відповідно мінімальну ширину і висоту
  • layout_constraintWidth_max і layout_constraintHeight_max: представляють відповідно максимальну ширину і висоту

Як значення вони приймають точне значення в dp або значення wrap (аналогічно wrap_content). Наприклад:

<TextView
    android:layout_width="260dp"
    android:layout_height="wrap_content"
    android:text="Hello Android"
    android:textSize="30sp"
    android:background="#e0e0e0"
 
    app:layout_constraintHeight_max="200dp"
    app:layout_constraintWidth_max="200dp"
    app:layout_constraintHeight_min="wrap"
    app:layout_constraintWidth_min="wrap"
 
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"/>

Хоча в цьому разі ширина TextView встановлена в 260dp, оскільки максимальна ширина задана в 200dp, то реальна ширина не перевищить 200dp.

Розміри у відсотках

Атрибут layout_constraintWidth_percent задає ширину елемента у відсотках по відношенню до доступного простору по горизонталі. Аналогічно атрибут layout_constraintHeight_percent задає висоту у відсотках щодо доступного простору по вертикалі.

Для їх застосування необхідно дотриматися таких умов:

  • Відповідний атрибут для встановлення розміру (android:layout_width - якщо ми встановлюємо ширину або android:layout_height - якщо ми встановлюємо висоту у відсотках) повинен мати значення MATCH_CONSTRAINT або 0dp.
  • Також необхідно встановити атрибут app:layout_constraintWidth_default="percent" при встановленні ширини і app:layout_constraintHeight_default="percent" при встановленні висоти.
  • Як значення атрибути layout_constraintWidth_percent і layout_constraintHeight_percent приймають дробове число від 0 до 1.

Наприклад, нехай TextView займає по вертикалі 25%, а по горизонталі 50% простору:

<?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="0dp"
        android:layout_height="0dp"
        android:text="Hello Android"
        android:textSize="30sp"
        android:background="#e0e0e0"
         
        app:layout_constraintWidth_default="percent"
        app:layout_constraintHeight_default="percent"
         
        app:layout_constraintWidth_percent="0.5"
        app:layout_constraintHeight_percent="0.25"
         
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
 
</androidx.constraintlayout.widget.ConstraintLayout>

Інший приклад - пропорційний поділ простору між кількома елементами:

<?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:hint="Введите Email"
        android:layout_height="wrap_content"
         
        android:layout_width="0dp"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent="0.66"
         
        app:layout_constraintRight_toLeftOf="@+id/button"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/button"
        android:text="Отправить"
        android:layout_height="wrap_content"
         
        android:layout_width="0dp"
        app:layout_constraintWidth_default="percent"
        app:layout_constraintWidth_percent="0.33"
         
        app:layout_constraintLeft_toRightOf="@id/editText"
        app:layout_constraintTop_toTopOf="parent" />
 
</androidx.constraintlayout.widget.ConstraintLayout>

У цьому разі текстове поле EditText займатиме 66%, а кнопка - 33% ширини:

Встановлення співвідношення висоти та ширини

ConstraintLayout також дає змогу встановлювати в елементів висоту відносно ширини / ширину відносно висоти. Для цього застосовується атрибут layout_constraintDimensionRatio. Як значення він приймає відношення у вигляді Width:Height, наприклад, 1:0.5 - тут число 1 представляє ширину, а 0.5 - висоту. Тобто ширина буде вдвічі більшою за висоту. Але при цьому хоча б для одного виміру має бути встановлено 0dp (MATCH_CONSTRAINT). Наприклад:

<?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="0dp"
        android:text="Hello Android"
        android:textSize="30sp"
        android:background="#e0e0e0"
        app:layout_constraintDimensionRatio="1:0.6"
 
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>
 
</androidx.constraintlayout.widget.ConstraintLayout>

У цьому разі ширина TextView буде такою, яка необхідна для його вмісту, а висота 60% від ширини.

Якщо і для ширини, і для висоти встановлено 0dp, то в цьому випадку система вибере найбільший вимір, що відповідає всім обмеженням, і відносно нього встановить значення іншого виміру. Щоб конкретизувати вимір, щодо якого йтиме розрахунок, можна вказати символ W (ширина) або H (висота). Наприклад:

<TextView
    android:layout_width="0dp"
    android:layout_height="0dp"
    android:text="Hello Android"
    android:textSize="30sp"
    android:background="#e0e0e0"
         
    app:layout_constraintDimensionRatio="W, 1:4"
 
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"/>

У цьому разі ширина буде в 4 рази меншою за висоту.