В Compose вы можете объединить несколько модификаторов, чтобы изменить внешний вид составного объекта. Эти цепочки модификаторов могут влиять на ограничения , передаваемые компонуемым объектам, которые определяют границы ширины и высоты.
На этой странице описывается, как связанные модификаторы влияют на ограничения и, в свою очередь, на измерение и размещение составных элементов.
Модификаторы в дереве пользовательского интерфейса
Чтобы понять, как модификаторы влияют друг на друга, полезно визуализировать, как они отображаются в дереве пользовательского интерфейса, которое создается на этапе композиции. Более подробную информацию смотрите в разделе Состав .
В дереве пользовательского интерфейса вы можете визуализировать модификаторы как узлы-оболочки для узлов макета:
![Код для составных элементов и модификаторов, а также их визуальное представление в виде дерева пользовательского интерфейса.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/modifier-wrapping.png?authuser=0000&hl=ru)
Добавление более одного модификатора к составному элементу создает цепочку модификаторов. Когда вы объединяете несколько модификаторов, каждый узел модификатора оборачивает остальную часть цепочки и узел макета внутри . Например, когда вы связываете clip
и модификатор size
, узел модификатора clip
оборачивает узел модификатора size
, который затем оборачивает узел макета Image
.
На этапе компоновки алгоритм обхода дерева остается прежним, но также посещается каждый узел модификатора. Таким образом, модификатор может изменить требования к размеру и размещение модификатора или узла макета, который он обертывает.
Как показано на рисунке 2, реализация составных элементов Image
и Text
состоит из цепочки модификаторов, обертывающих один узел макета. Реализации Row
и Column
— это просто узлы макета, которые описывают, как размещать их дочерние элементы.
![Древовидная структура была прежней, но теперь каждый узел представляет собой просто макет с множеством узлов-модификаторов, окружающих его.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/composables-modifiers.png?authuser=0000&hl=ru)
Подводя итог:
- Модификаторы оборачивают один модификатор или узел макета.
- Узлы макета могут размещать несколько дочерних узлов.
В следующих разделах описывается, как использовать эту ментальную модель для анализа цепочки модификаторов и как она влияет на размер составных элементов.
Ограничения на этапе макетирования
Фаза макета следует трехэтапному алгоритму для определения ширины, высоты и координаты x, y каждого узла макета:
- Измерить дочерние элементы : узел измеряет своих дочерних элементов, если таковые имеются.
- Определите собственный размер : на основе этих измерений узел определяет свой собственный размер.
- Разместить дочерние элементы : каждый дочерний узел размещается относительно собственной позиции узла.
Constraints
помогают найти правильные размеры узлов на первых двух шагах алгоритма. Ограничения определяют минимальные и максимальные границы ширины и высоты узла. Когда узел определяет свой размер, его измеренный размер должен находиться в пределах этого диапазона размеров.
Типы ограничений
Ограничение может быть одним из следующих:
- Ограниченный : узел имеет максимальную и минимальную ширину и высоту.
![Ограниченные ограничения разных размеров внутри контейнера.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/bounded-constraints.png?authuser=0000&hl=ru)
- Неограниченный : размер узла не ограничен. Максимальные границы ширины и высоты установлены на бесконечность.
![Неограниченные ограничения, у которых ширина и высота равны бесконечности. Ограничения выходят за пределы контейнера.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/unbounded-constraints.png?authuser=0000&hl=ru)
- Точный : узлу предлагается следовать точным требованиям к размеру. Минимальная и максимальная границы установлены на одно и то же значение.
![Точные ограничения, соответствующие точным требованиям к размеру внутри контейнера.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/exact-constraints.png?authuser=0000&hl=ru)
- Комбинация : узел следует за комбинацией вышеуказанных типов ограничений. Например, ограничение может ограничивать ширину, допуская при этом неограниченную максимальную высоту, или устанавливать точную ширину, но обеспечивать ограниченную высоту.
![Два контейнера, которые показывают комбинации ограниченных и неограниченных ограничений, а также точную ширину и высоту.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/combination-constraints.png?authuser=0000&hl=ru)
В следующем разделе описывается, как эти ограничения передаются от родителя к дочернему элементу.
Как ограничения передаются от родителя к дочернему элементу
На первом этапе алгоритма, описанного в разделе «Ограничения на этапе макета» , ограничения передаются от родительского элемента к дочернему в дереве пользовательского интерфейса.
Когда родительский узел измеряет свои дочерние узлы, он предоставляет эти ограничения каждому дочернему узлу, чтобы они знали, насколько большими или маленькими им разрешено быть. Затем, когда он сам определяет свой размер, он также придерживается ограничений, введенных его собственными родителями.
На высоком уровне алгоритм работает следующим образом:
- Чтобы определить размер, который он действительно хочет занимать, корневой узел в дереве пользовательского интерфейса измеряет свои дочерние элементы и пересылает те же ограничения своему первому дочернему элементу.
- Если дочерний элемент является модификатором, который не влияет на измерение, он передает ограничения следующему модификатору. Ограничения передаются по цепочке модификаторов как есть, пока не будет достигнут модификатор, влияющий на измерение. Затем размеры ограничений соответственно изменяются.
- Как только достигается узел, не имеющий дочерних элементов (называемый «листовым узлом»), он определяет его размер на основе переданных ограничений и возвращает этот разрешенный размер своему родительскому элементу.
- Родительский элемент адаптирует свои ограничения на основе измерений этого дочернего элемента и вызывает своего следующего дочернего элемента с этими скорректированными ограничениями.
- После того, как все дочерние элементы родительского узла измерены, родительский узел определяет свой собственный размер и сообщает об этом своему родительскому узлу.
- Таким образом, все дерево просматривается в глубину. В конце концов, все узлы определились со своими размерами, и этап измерения завершен.
Подробный пример см. в видеоролике «Ограничения и порядок модификаторов» .
Модификаторы, влияющие на ограничения
В предыдущем разделе вы узнали, что некоторые модификаторы могут влиять на размер ограничения. В следующих разделах описаны конкретные модификаторы, влияющие на ограничения.
модификатор size
Модификатор size
объявляет предпочтительный размер содержимого.
Например, следующее дерево пользовательского интерфейса должно отображаться в контейнере размером 300dp
на 200dp
. Ограничения ограничены, что позволяет использовать ширину от 100dp
до 300dp
и высоту от 100dp
до 200dp
:
![Часть дерева пользовательского интерфейса с модификатором размера, обертывающим узел макета, и представлением ограниченных ограничений, установленных модификатором размера в контейнере.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/size-modifier.png?authuser=0000&hl=ru)
Модификатор size
адаптирует входящие ограничения в соответствии с переданным ему значением. В этом примере значение равно 150dp
:
![То же, что на рисунке 7, за исключением того, что модификатор размера адаптирует входящие ограничения в соответствии с переданным в него значением.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/size-modifier-2.png?authuser=0000&hl=ru)
size
, настраивающий ограничения на 150dp
.Если ширина и высота меньше, чем граница наименьшего ограничения, или больше, чем граница наибольшего ограничения, модификатор соответствует переданным ограничениям настолько точно, насколько это возможно, при этом все еще придерживаясь переданных ограничений:
![Два дерева пользовательского интерфейса и соответствующие им представления в контейнерах. В первом модификатор размера принимает входящие ограничения; во втором модификатор размера максимально точно адаптируется к слишком большим ограничениям, в результате чего ограничения заполняют контейнер.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/size-modifier-3.png?authuser=0000&hl=ru)
size
, максимально точно соответствующий переданному ограничению. Обратите внимание, что объединение нескольких модификаторов size
в цепочку не работает. Первый модификатор size
устанавливает фиксированное значение как минимального, так и максимального ограничения. Даже если второй модификатор размера запрашивает меньший или больший размер, он все равно должен соответствовать точным переданным границам, поэтому он не будет переопределять эти значения:
![Цепочка из двух модификаторов размера в дереве пользовательского интерфейса и его представление в контейнере, которое является результатом передачи первого значения, а не второго значения.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/size-modifier-4.png?authuser=0000&hl=ru)
size
, в которой переданное второе значение ( 50dp
) не переопределяет первое значение ( 100dp
). модификатор requiredSize
Используйте модификатор requiredSize
вместо size
если вам нужно, чтобы ваш узел переопределял входящие ограничения. Модификатор requiredSize
заменяет входящие ограничения и передает указанный вами размер как точные границы.
Когда размер передается обратно вверх по дереву, дочерний узел будет центрирован в доступном пространстве:
![Модификатор size и requireSize связаны в дереве пользовательского интерфейса и соответствующее представление в контейнере. Ограничения модификатора требуемого размера переопределяют ограничения модификатора размера.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/requiredsize-modifier.png?authuser=0000&hl=ru)
requiredSize
, переопределяющий входящие ограничения модификатора size
. модификаторы width
и height
Модификатор size
адаптирует как ширину, так и высоту ограничений. С помощью модификатора width
вы можете установить фиксированную ширину, но оставить неопределенную высоту. Аналогично, с помощью модификатора height
вы можете установить фиксированную высоту, но оставить ширину неопределенной:
![Два дерева пользовательского интерфейса: одно с модификатором ширины и его представлением в контейнере, а другое с модификатором высоты и его представлением.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/width-height-modifier.png?authuser=0000&hl=ru)
width
и модификатор height
, задающие фиксированную ширину и высоту соответственно. модификатор sizeIn
Модификатор sizeIn
позволяет вам установить точные минимальные и максимальные ограничения для ширины и высоты. Используйте модификатор sizeIn
, если вам нужен детальный контроль над ограничениями.
![Дерево пользовательского интерфейса с модификатором sizeIn с установленными минимальной и максимальной шириной и высотой и его представлением в контейнере.](https://developer.android.com/static/develop/ui/compose/images/layouts/constraints-modifiers/sizein-modifier.png?authuser=0000&hl=ru)
sizeIn
с установленными minWidth
, maxWidth
, minHeight
и maxHeight
.Примеры
В этом разделе показаны и объяснены выходные данные нескольких фрагментов кода со связанными модификаторами.
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .fillMaxSize() .size(50.dp) )
Этот фрагмент выдает следующий результат:
- Модификатор
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) )
Этот фрагмент выдает следующий результат:
- Модификатор
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) )
Этот фрагмент выдает следующий результат:
- Модификатор
clip
не меняет ограничения.- Модификатор
padding
снижает максимальные ограничения. - Модификатор
size
устанавливает все ограничения на100dp
. -
Image
соответствует этим ограничениям и имеет размер100
на100dp
. - Модификатор
padding
добавляет10dp
ко всем размерам, поэтому увеличивает сообщаемую ширину и высоту на20dp
. - Теперь на этапе рисования модификатор
clip
действует на холсте размером120
на120dp
. Итак, он создает круглую маску такого размера . - Модификатор
padding
затем вставляет свое содержимое на10dp
для всех размеров, поэтому он уменьшает размер холста до100
на100dp
. -
Image
нарисовано на этом холсте. Изображение обрезается на основе исходного круга с разрешением120dp
, поэтому на выходе получается некруглый результат.
- Модификатор