Ограничения и порядок модификаторов

В Compose можно объединять несколько модификаторов, чтобы изменять внешний вид и функциональность составного объекта. Эти цепочки модификаторов могут влиять на ограничения, передаваемые составным объектам, которые определяют границы ширины и высоты.

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

Модификаторы в дереве пользовательского интерфейса

Чтобы понять, как модификаторы влияют друг на друга, полезно визуализировать их отображение в дереве пользовательского интерфейса, которое генерируется на этапе композиции. Для получения дополнительной информации см. раздел «Композиция» .

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

Код для композиционных элементов и модификаторов, а также их визуальное представление в виде дерева пользовательского интерфейса.
Рисунок 1. Модификаторы, оборачивающие узлы компоновки в дереве пользовательского интерфейса.

Добавление более одного модификатора к составному элементу создает цепочку модификаторов. При объединении нескольких модификаторов каждый узел модификатора инкапсулирует остальную часть цепочки и узел компоновки . Например, при объединении модификатора clip и модификатора size узел модификатора clip инкапсулирует узел модификатора size , который затем инкапсулирует узел компоновки Image .

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

Как показано на рисунке 2, реализация самих составных элементов Image и Text представляет собой цепочку модификаторов, охватывающих один узел компоновки.

Объекты Row и Column представляют собой узлы компоновки, описывающие, как размещать дочерние элементы.

Древовидная структура осталась прежней, но теперь каждый узел представляет собой простую схему, окруженную множеством узлов-модификаторов.
Рисунок 2. Та же древовидная структура, что и на рисунке 1, но с элементами, входящими в состав дерева пользовательского интерфейса, визуализированными в виде цепочек модификаторов.

В заключение:

  • Модификаторы представляют собой обертки для одного модификатора или узла компоновки.
  • Узлы компоновки могут размещать несколько дочерних узлов.

В следующих разделах описывается, как использовать эту ментальную модель для рассуждений о цепочках модификаторов и о том, как она влияет на размер составных элементов.

Ограничения на этапе компоновки.

На этапе компоновки используется трехэтапный алгоритм для определения ширины, высоты и координат x, y каждого узла компоновки:

  1. Измерение дочерних узлов : узел измеряет количество своих дочерних узлов, если таковые имеются.
  2. Определение собственного размера : На основе этих измерений узел определяет свой собственный размер.
  3. Размещение дочерних узлов : Каждый дочерний узел размещается относительно собственного положения узла.

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

Типы ограничений

Ограничение может быть одним из следующих:

  • Ограничения : Узел имеет максимальную и минимальную ширину и высоту.
Ограничения по размерам для контейнеров.
Рисунок 3. Ограничения.
  • Без ограничений : размер узла не ограничен никакими параметрами. Максимальная ширина и высота установлены на бесконечность.
Неограниченные параметры, ширина и высота которых заданы как бесконечность. Эти параметры выходят за пределы контейнера.
Рисунок 4. Неограниченные ограничения.
  • Точное значение : Узлу задается точное требование к размеру. Минимальный и максимальный пределы устанавливаются на одно и то же значение.
Точные ограничения, соответствующие требуемым размерам контейнера.
Рисунок 5. Точные ограничения.
  • Комбинация : Узел соответствует комбинации описанных выше типов ограничений. Например, ограничение может ограничивать ширину, допуская при этом неограниченную максимальную высоту, или задавать точную ширину, но ограничивать высоту.
Два контейнера, демонстрирующие комбинации ограниченных и неограниченных условий, а также точные значения ширины и высоты.
Рисунок 6. Комбинации ограниченных и неограниченных условий, а также точных значений ширины и высоты.

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

Как ограничения передаются от родителя к ребенку

На первом этапе алгоритма, описанного в разделе «Ограничения на этапе компоновки» , ограничения передаются от родительского элемента к дочернему в дереве пользовательского интерфейса.

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

В общих чертах алгоритм работает следующим образом:

  1. Чтобы определить фактический размер, который он хочет занять, корневой узел в дереве пользовательского интерфейса измеряет свои дочерние элементы и передает те же ограничения своему первому дочернему элементу.
  2. Если дочерний модификатор не влияет на измерение, он передает ограничения следующему модификатору. Ограничения передаются по цепочке модификаторов как есть, если только не встречается модификатор, влияющий на измерение. В этом случае ограничения изменяются в соответствии с заданными параметрами.
  3. Как только достигается узел, не имеющий дочерних элементов (называемый «листовым узлом»), он определяет свой размер на основе переданных ограничений и возвращает этот определенный размер своему родительскому узлу.
  4. Родительский процесс корректирует свои ограничения на основе измерений дочернего процесса и вызывает следующий дочерний процесс с этими скорректированными ограничениями.
  5. После того как размеры всех дочерних узлов родительского узла будут измерены, родительский узел определяет свой собственный размер и сообщает об этом своему родительскому узлу.
  6. Таким образом, дерево обходится в глубину. В конечном итоге, все узлы определяют свои размеры, и этап измерения завершается.

Для более подробного примера посмотрите видеоролик «Ограничения и порядок модификаторов» .

Модификаторы, влияющие на ограничения

В предыдущем разделе вы узнали, что некоторые модификаторы могут влиять на размер ограничений. В следующих разделах описаны конкретные модификаторы, влияющие на ограничения.

Модификатор size

Модификатор size определяет предпочтительный размер содержимого.

Например, следующее дерево элементов пользовательского интерфейса должно отображаться в контейнере размером 300dp на 200dp . Ограничения являются граничными, допуская ширину от 100dp до 300dp и высоту от 100dp до 200dp :

Часть дерева пользовательского интерфейса с модификатором размера, охватывающим узел компоновки, и представление ограничений, установленных модификатором размера в контейнере.
Рисунок 7. Ограничения в дереве пользовательского интерфейса и его представление в контейнере.

Модификатор size адаптирует входящие ограничения в соответствии с переданным ему значением. В этом примере значение равно 150dp :

Аналогично рисунку 7, за исключением того, что модификатор размера адаптирует входящие ограничения в соответствии со значением, переданным ему.
Рисунок 8. Модификатор size , корректирующий ограничения до 150dp .

Если ширина и высота меньше наименьшего ограничения или больше наибольшего ограничения, модификатор максимально точно соответствует переданным ограничениям, при этом соблюдая заданные ограничения:

Два дерева пользовательского интерфейса и их соответствующие представления в контейнерах. В первом случае модификатор размера принимает входящие ограничения; во втором же модификатор размера максимально точно адаптируется к слишком большим ограничениям, в результате чего ограничения заполняют контейнер.
Рисунок 9. Модификатор size , максимально точно соответствующий заданному ограничению.

Обратите внимание, что последовательное использование нескольких модификаторов size не работает. Первый модификатор size устанавливает как минимальное, так и максимальное ограничения на фиксированное значение. Даже если второй модификатор размера запрашивает меньший или больший размер, он все равно должен точно соответствовать переданным границам, поэтому он не будет переопределять эти значения:

Цепочка из двух модификаторов размера в дереве пользовательского интерфейса и ее представление в контейнере, которая является результатом первого переданного значения, а не второго.
Рисунок 10. Цепочка из двух модификаторов size , в которой второе переданное значение ( 50dp ) не переопределяет первое значение ( 100dp ).

Модификатор requiredSize

Используйте модификатор requiredSize вместо size , если вам нужно, чтобы ваш узел переопределял входящие ограничения. Модификатор requiredSize заменяет входящие ограничения и передает указанный вами размер в качестве точных границ.

Когда размер передается обратно вверх по дереву, дочерний узел будет центрирован в доступном пространстве:

Модификаторы size и requiredSize объединены в древовидную структуру пользовательского интерфейса, а соответствующее представление находится в контейнере. Ограничения модификатора requiredSize переопределяют ограничения модификатора size.
Рисунок 11. Модификатор requiredSize , переопределяющий входящие ограничения из модификатора size .

Модификаторы width и height

Модификатор size изменяет как ширину, так и высоту ограничений. С помощью модификатора width можно задать фиксированную ширину, но оставить высоту неопределенной. Аналогично, с помощью модификатора height можно задать фиксированную высоту, но оставить ширину неопределенной.

Два дерева пользовательского интерфейса: одно с модификатором ширины и его представлением в контейнере, а другое — с модификатором высоты и его представлением.
Рисунок 12. Модификатор width и модификатор height , задающие фиксированную ширину и высоту соответственно.

Модификатор sizeIn

Модификатор sizeIn позволяет задать точные минимальные и максимальные значения ширины и высоты. Используйте модификатор sizeIn если вам необходим более точный контроль над ограничениями.

Древовидная структура пользовательского интерфейса с модификатором sizeIn, определяющим минимальную и максимальную ширину и высоту, и её представление внутри контейнера.
Рисунок 13. Модификатор sizeIn с заданными значениями minWidth , maxWidth , minHeight и maxHeight .

Примеры

В этом разделе показаны и объяснены результаты выполнения нескольких фрагментов кода с цепочками модификаторов.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .size(50.dp)
)

Этот фрагмент кода выдает следующий результат:

Синий квадрат, заполняющий родительский контейнер.
Рисунок 14. Image заполняет максимальный размер в результате применения цепочки модификаторов.
  • Модификатор fillMaxSize изменяет ограничения, устанавливая минимальную ширину и высоту на максимальные значения — 300dp по ширине и 200dp по высоте.
  • Даже если модификатор size хочет использовать размер 50dp , он все равно должен соблюдать входящие минимальные ограничения. Поэтому модификатор size также выдаст точные границы ограничения 300 на 200 , фактически игнорируя значение, указанное в модификаторе size .
  • Image соответствует этим границам и имеет размер 300 на 200 , который передается по всей структуре дерева.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .fillMaxSize()
        .wrapContentSize()
        .size(50.dp)
)

Этот фрагмент кода выдает следующий результат:

Небольшой синий квадрат, расположенный по центру родительского контейнера.
Рисунок 15. Image центрировано и имеет размер 50dp .
  • Модификатор fillMaxSize адаптирует ограничения, устанавливая минимальную ширину и высоту на максимальное значение — 300dp по ширине и 200dp по высоте.
  • Модификатор wrapContentSize сбрасывает минимальные ограничения. Таким образом, если fillMaxSize приводил к фиксированным ограничениям, то wrapContentSize возвращает их к ограниченным . Следующий узел теперь может снова занимать все пространство или быть меньше всего пространства.
  • Модификатор size устанавливает ограничения на минимальное и максимальное значения, равные 50 .
  • Image имеет размер 50 на 50 , и модификатор size передает это значение дальше.
  • Модификатор wrapContentSize обладает особым свойством. Он помещает свой дочерний элемент в центр минимальных доступных границ , которые были ему переданы. Таким образом, размер, который он сообщает своим родительским элементам, равен минимальным границам, переданным ему.

Комбинируя всего три модификатора, вы можете задать размер для составного элемента и центрировать его относительно родительского элемента.

Image(
    painterResource(R.drawable.hero),
    contentDescription = null,
    Modifier
        .clip(CircleShape)
        .padding(10.dp)
        .size(100.dp)
)

Этот фрагмент кода выдает следующий результат:

Круглая форма, которая некорректно обрезается из-за порядка модификаторов.
Рисунок 16. Неправильно обрезанная фигура из-за порядка модификаторов.
  • Модификатор clip не изменяет ограничения.
  • Модификатор padding уменьшает максимальные ограничения.
  • Модификатор size устанавливает все ограничения на 100dp .
  • Image соответствует этим ограничениям и имеет размер 100dp на 100dp .
  • Модификатор padding добавляет 10dp со всех сторон к размеру, указанному элементом Image , поэтому макет с padding отображает ширину и высоту 120dp .
  • Теперь, на этапе рисования, модификатор clip воздействует на холст размером 120dp на 120dp . Он создает маску в виде круга такого размера.
  • Модификатор padding затем вставляет содержимое на 10dp со всех сторон, что уменьшает размер холста для Image до 100dp на 100dp .
  • Image рисуется на этом меньшем холсте. Изображение обрезается относительно исходного круга размером 120dp , поэтому на выходе получается некруглое изображение.