В Compose можно объединять несколько модификаторов, чтобы изменять внешний вид и поведение компонента. Эти цепочки модификаторов могут влиять на ограничения, передаваемые в компонуемые функции, которые определяют границы ширины и высоты.
На этой странице рассказывается, как цепочки модификаторов влияют на ограничения и, следовательно, на измерение и размещение композиций.
Модификаторы в дереве интерфейса
Чтобы понять, как модификаторы влияют друг на друга, полезно представить, как они выглядят в дереве интерфейса, которое создается на этапе композиции. Подробнее о составе сегмента аудитории…
В дереве интерфейса можно визуализировать модификаторы как узлы-обертки для узлов макета:
Если добавить к компонуемому элементу несколько модификаторов, они будут применяться последовательно. При объединении нескольких модификаторов каждый узел модификатора оборачивает остальную часть цепочки и узел макета. Например, при объединении модификаторов clip и size узел модификатора clip будет содержать узел модификатора size, который, в свою очередь, будет содержать узел макета Image.
На этапе макета алгоритм, который проходит по дереву, остается прежним, но посещаются также все узлы модификаторов. Таким образом, модификатор может изменять требования к размеру и размещению модификатора или узла макета, который он оборачивает.
Как показано на рисунке 2, реализация композиций Image и Text состоит из цепочки модификаторов, которые оборачивают один узел макета.
Реализации Row и Column представляют собой узлы макета, которые описывают, как размещать дочерние элементы.
Кратко:
- Модификаторы оборачивают один модификатор или узел макета.
- Узлы макета могут размещать несколько дочерних узлов.
В следующих разделах рассказывается, как использовать эту ментальную модель для рассуждений о цепочках модификаторов и о том, как они влияют на размер композиций.
Ограничения на этапе макета
На этапе макета используется трехшаговый алгоритм, чтобы определить ширину, высоту и координаты X и Y каждого узла макета:
- Измерение дочерних элементов. Узел измеряет свои дочерние элементы, если они есть.
- Определить собственный размер. На основе этих измерений узел определяет собственный размер.
- Разместить дочерние элементы. Каждый дочерний элемент размещается относительно позиции родительского элемента.
Constraints помогают определить подходящие размеры узлов на первых двух этапах алгоритма. Ограничения определяют минимальную и максимальную ширину и высоту узла. Когда узел определяет свой размер, его измеренный размер должен находиться в этом диапазоне.
Типы ограничений
Ограничение может быть одним из следующих:
- Ограниченный. У узла есть максимальная и минимальная ширина и высота.
- Неограниченный. Размер узла не ограничен. Максимальная ширина и высота не ограничены.
- Точное соответствие. Узел должен соответствовать точному требованию к размеру. Минимальное и максимальное значения заданы одинаковыми.
- Комбинация – узел соответствует комбинации перечисленных выше типов ограничений. Например, можно ограничить ширину, но не высоту, или задать точную ширину и ограниченную высоту.
В следующем разделе описано, как эти ограничения передаются от родительского элемента дочернему.
Как ограничения передаются от родительского элемента к дочернему
На первом этапе алгоритма, описанного в разделе Ограничения на этапе макета, ограничения передаются от родительского элемента к дочернему в дереве интерфейса.
Когда родительский узел измеряет дочерние, он передает им ограничения, чтобы они знали, какими могут быть. При определении собственного размера он также учитывает ограничения, переданные родительскими элементами.
Общий принцип работы алгоритма:
- Чтобы определить, какой размер должен занимать корневой узел в дереве интерфейса, он измеряет дочерние узлы и передает те же ограничения первому дочернему узлу.
- Если дочерний элемент является модификатором, который не влияет на измерение, он передает ограничения следующему модификатору. Ограничения передаются по цепочке модификаторов без изменений, пока не будет достигнут модификатор, влияющий на измерение. Затем ограничения будут изменены соответствующим образом.
- Когда узел достигает конечного узла (узла без дочерних элементов), он определяет свой размер на основе переданных ограничений и возвращает этот размер родительскому узлу.
- Родительский элемент корректирует свои ограничения на основе размеров дочернего элемента и вызывает следующий дочерний элемент с этими скорректированными ограничениями.
- Когда все дочерние узлы родительского узла будут измерены, родительский узел определяет свой размер и передает его своему родительскому узлу.
- Таким образом, все дерево будет пройдено в глубину. В конце концов все узлы определяют свои размеры, и этап измерения завершается.
Подробнее о порядке применения ограничений и модификаторов…
Модификаторы, влияющие на ограничения
В предыдущем разделе вы узнали, что некоторые модификаторы могут влиять на размер ограничения. В следующих разделах описаны модификаторы, влияющие на ограничения.
Модификатор size
Модификатор size задает предпочтительный размер контента.
Например, следующее дерево интерфейса должно быть отрисовано в контейнере 300dp с помощью 200dp. Ограничения позволяют использовать ширину от 100dp до 300dp и высоту от 100dp до 200dp:
Модификатор size адаптирует входящие ограничения в соответствии со значением, переданным ему.
В этом примере значением является 150dp:
size, который корректирует ограничения до 150dp.Если ширина и высота меньше минимального или больше максимального ограничения, модификатор будет соответствовать переданным ограничениям настолько, насколько это возможно:
size, который максимально точно соответствует переданному ограничению.Обратите внимание, что объединять несколько модификаторов size нельзя. Первый модификатор size
устанавливает минимальное и максимальное ограничения на фиксированное значение. Даже если второй модификатор размера запрашивает меньший или больший размер, он все равно должен соответствовать точным границам, переданным в запросе, поэтому он не переопределит эти значения:
size, в которой второе переданное значение (50dp) не переопределяет первое значение (100dp).Модификатор requiredSize
Используйте модификатор requiredSize вместо size, если вам нужно, чтобы узел переопределил входящие ограничения. Модификатор requiredSize заменяет входящие ограничения и передает указанный вами размер в качестве точных границ.
Когда размер передается вверх по дереву, дочерний узел центрируется в доступном пространстве:
requiredSize переопределяет ограничения, заданные модификатором size.Модификаторы width и height
Модификатор size адаптирует как ширину, так и высоту ограничений. С помощью модификатора width можно задать фиксированную ширину, но не указывать высоту.
Аналогично, с помощью модификатора height можно задать фиксированную высоту, но оставить ширину неопределенной:
width и модификатор height, задающий фиксированную ширину и высоту соответственно.Модификатор sizeIn
Модификатор sizeIn позволяет задать точные минимальные и максимальные ограничения для ширины и высоты. Используйте модификатор sizeIn, если вам нужен более точный контроль над ограничениями.
sizeIn со значениями minWidth, maxWidth, minHeight и maxHeight.Примеры
В этом разделе показаны и объяснены результаты выполнения нескольких фрагментов кода с цепочками модификаторов.
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .fillMaxSize() .size(50.dp) )
Этот фрагмент кода выводит следующие данные:
Image заполняет максимальный размер в результате цепочки модификаторов.- Модификатор
fillMaxSizeизменяет ограничения, чтобы задать минимальную ширину и высоту, равные максимальному значению:300dpв ширину и200dpв высоту. - Несмотря на то что модификатор
sizeхочет использовать размер50dp, он должен соблюдать входящие минимальные ограничения. Таким образом, модификаторsizeтакже выведет точные границы ограничения300–200, фактически игнорируя значение, указанное в модификатореsize. Imageследует этим границам и сообщает о размере300x200, который передается вверх по дереву.
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .fillMaxSize() .wrapContentSize() .size(50.dp) )
Этот фрагмент кода выводит следующие данные:
Image" расположен по центру, размер 50dp.- Модификатор
fillMaxSizeадаптирует ограничения, чтобы задать для минимальной ширины и высоты максимальное значение:300dpдля ширины и200dpдля высоты. - Модификатор
wrapContentSizeсбрасывает минимальные ограничения. Таким образом, еслиfillMaxSizeприводит к фиксированным ограничениям, тоwrapContentSizeвозвращает их к ограниченным. Следующий узел может снова занимать все пространство или быть меньше него. - Модификатор
sizeзадает ограничения в виде минимального и максимального значений50. - Значение
Imageпреобразуется в размер50x50, а модификаторsizeпередает его дальше. - У модификатора
wrapContentSizeесть особое свойство. Он берет дочерний элемент и помещает его в центр доступных минимальных границ, которые были ему переданы. Таким образом, размер, который он передает родительским элементам, равен минимальным границам, переданным ему.
С помощью всего трех модификаторов можно задать размер composable-функции и центрировать ее в родительском элементе.
Image( painterResource(R.drawable.hero), contentDescription = null, Modifier .clip(CircleShape) .padding(10.dp) .size(100.dp) )
Этот фрагмент кода выводит следующие данные:
- Модификатор
clipне меняет ограничения. - Модификатор
paddingснижает максимальные ограничения. - Модификатор
sizeустанавливает для всех ограничений значение100dp. Imageсоблюдает эти ограничения и сообщает о размере100dpx100dp.- Модификатор
paddingдобавляет10dpсо всех сторон к размеру, указанному вImage, поэтому макет с отступами будет иметь ширину и высоту120dp. - Теперь в режиме рисования модификатор
clipдействует на холсте размером120dpx120dp. Будет создана круглая маска указанного размера. - Модификатор
paddingвставляет контент на10dpсо всех сторон, поэтому размер холста дляImageуменьшается до100dpна100dp. - На этом небольшом холсте нарисован
Image. Изображение обрезается по исходному кругу120dp, поэтому результат получается не круглым.