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

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

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

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

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

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

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

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

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

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

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

Подводя итог:

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

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

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

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

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

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

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

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

  • Ограниченный : узел имеет максимальную и минимальную ширину и высоту.
Ограничения разных размеров внутри контейнера.
Рисунок 3. Ограничения.
  • Неограниченный : узел не ограничен никаким размером. Максимальные границы ширины и высоты установлены на бесконечность.
Неограниченные ограничения, имеющие ширину и высоту, равные бесконечности. Ограничения выходят за пределы контейнера.
Рисунок 4. Неограниченные ограничения.
  • Exact : Узел должен следовать точному требованию размера. Минимальные и максимальные границы устанавливаются на одно и то же значение.
Точные ограничения, соответствующие точным требованиям к размеру внутри контейнера.
Рисунок 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 заменяет входящие ограничения и передает указанный вами размер в качестве точных границ.

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

Размер и модификатор requiredSize, объединенные в дерево пользовательского интерфейса, и соответствующее представление в контейнере. Ограничения модификатора requiredSize переопределяют ограничения модификатора размера.
Рисунок 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)
)

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

  • Модификатор 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 , поэтому на выходе получается некруглый результат.
,

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

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

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

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

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

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

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

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

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

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

Подводя итог:

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

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

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

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

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

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

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

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

  • Ограниченный : узел имеет максимальную и минимальную ширину и высоту.
Ограничения разных размеров внутри контейнера.
Рисунок 3. Ограничения.
  • Неограниченный : узел не ограничен никаким размером. Максимальные границы ширины и высоты установлены на бесконечность.
Неограниченные ограничения, имеющие ширину и высоту, равные бесконечности. Ограничения выходят за пределы контейнера.
Рисунок 4. Неограниченные ограничения.
  • Exact : Узел должен следовать точному требованию размера. Минимальные и максимальные границы устанавливаются на одно и то же значение.
Точные ограничения, соответствующие точным требованиям к размеру внутри контейнера.
Рисунок 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 заменяет входящие ограничения и передает указанный вами размер в качестве точных границ.

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

Размер и модификатор requiredSize, объединенные в дерево пользовательского интерфейса, и соответствующее представление в контейнере. Ограничения модификатора requiredSize переопределяют ограничения модификатора размера.
Рисунок 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)
)

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

  • Модификатор 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 , поэтому на выходе получается некруглый результат.
,

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

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

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

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

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

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

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

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

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

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

Подводя итог:

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

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

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

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

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

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

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

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

  • Ограниченный : узел имеет максимальную и минимальную ширину и высоту.
Ограничения разных размеров внутри контейнера.
Рисунок 3. Ограничения.
  • Неограниченный : узел не ограничен никаким размером. Максимальные границы ширины и высоты установлены на бесконечность.
Неограниченные ограничения, имеющие ширину и высоту, равные бесконечности. Ограничения выходят за пределы контейнера.
Рисунок 4. Неограниченные ограничения.
  • Exact : Узел должен следовать точному требованию размера. Минимальные и максимальные границы устанавливаются на одно и то же значение.
Точные ограничения, соответствующие точным требованиям к размеру внутри контейнера.
Рисунок 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 заменяет входящие ограничения и передает размер, который вы указываете в качестве точных границ.

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

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

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

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

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

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

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

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

Примеры

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

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 , поэтому выход не является раундовым результатом.