В Compose элементы пользовательского интерфейса представлены компонуемыми функциями, которые при вызове генерируют фрагмент пользовательского интерфейса, который затем добавляется в дерево пользовательского интерфейса, отображаемое на экране. Каждый элемент пользовательского интерфейса имеет одного родителя и потенциально много дочерних элементов. Каждый элемент также расположен внутри своего родителя, что указывается в виде позиции (x, y) и размера, заданного в виде width и height .
Родительские элементы определяют ограничения для своих дочерних элементов. Элементу предлагается указать свой размер в рамках этих ограничений. Ограничения определяют минимальную и максимальную width и height элемента. Если у элемента есть дочерние элементы, он может измерить каждый из них, чтобы определить свой размер. После того как элемент определит и сообщит свой собственный размер, у него появляется возможность определить, как размещать свои дочерние элементы относительно себя, как подробно описано в разделе «Создание пользовательских макетов» .
Размещение каждого узла в дереве пользовательского интерфейса — это трехэтапный процесс. Каждый узел должен:
- Измерьте любых детей.
- Определите его размер самостоятельно.
- Поместите своих детей
Использование областей видимости определяет , когда можно измерять и размещать дочерние элементы. Измерение компоновки может быть выполнено только во время проходов измерения и компоновки, а дочерний элемент может быть размещен только во время проходов компоновки (и только после того, как он был измерен). Благодаря областям видимости Compose, таким как MeasureScope и PlacementScope , это правило соблюдается на этапе компиляции.
Используйте модификатор макета.
Модификатор layout можно использовать для изменения способа измерения и размещения элемента. Layout — это лямбда-функция; её параметры включают измеряемый элемент, передаваемый как measurable , и входящие ограничения этого компонуемого объекта, передаваемые как constraints . Пользовательский модификатор layout может выглядеть следующим образом:
fun Modifier.customLayoutModifier() = layout { measurable, constraints -> // ... }
Отобразите Text на экране и управляйте расстоянием от верхней до базовой линии первой строки текста. Именно это делает модификатор paddingFromBaseline ; здесь вы реализуете его в качестве примера. Для этого используйте модификатор layout , чтобы вручную разместить составной элемент на экране. Вот результат, когда верхний отступ Text установлен на 24.dp :

paddingFromBaseline .Вот код для создания этого отступа:
fun Modifier.firstBaselineToTop( firstBaselineToTop: Dp ) = layout { measurable, constraints -> // Measure the composable val placeable = measurable.measure(constraints) // Check the composable has a first baseline check(placeable[FirstBaseline] != AlignmentLine.Unspecified) val firstBaseline = placeable[FirstBaseline] // Height of the composable with padding - first baseline val placeableY = firstBaselineToTop.roundToPx() - firstBaseline val height = placeable.height + placeableY layout(placeable.width, height) { // Where the composable gets placed placeable.placeRelative(0, placeableY) } }
Вот что происходит в этом коде:
- В параметре лямбда-функции,
measurable, вы измеряетеTextпредставленный этим параметром, вызываяmeasurable.measure(constraints). - Размер компонуемого элемента задается вызовом метода
layout(width, height), который также возвращает лямбда-функцию, используемую для размещения обернутых элементов. В данном случае это высота между последней базовой линией и добавленным верхним отступом. - Вы размещаете обёрнутые элементы на экране, вызывая метод
placeable.place(x, y). Если обёрнутые элементы не размещены, они не будут видны. Позиция по осиyсоответствует верхнему отступу: положению первой базовой линии текста.
Чтобы убедиться, что всё работает как положено, используйте этот модификатор на Text :
@Preview @Composable fun TextWithPaddingToBaselinePreview() { MyApplicationTheme { Text("Hi there!", Modifier.firstBaselineToTop(32.dp)) } } @Preview @Composable fun TextWithNormalPaddingPreview() { MyApplicationTheme { Text("Hi there!", Modifier.padding(top = 32.dp)) } }

Text и отображаемый в предварительном просмотре.Создание пользовательских макетов
Модификатор layout изменяет только вызывающий компонуемый объект. Для измерения и компоновки нескольких компонуемых объектов используйте вместо него компонуемый объект Layout . Этот компонуемый объект позволяет измерять и компоновать дочерние элементы вручную. Все компоновки более высокого уровня, такие как Column и Row создаются с помощью компонуемого Layout .
В этом примере создается очень простая версия Column . Большинство пользовательских макетов следуют этому шаблону:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // measure and position children given constraints logic here // ... } }
Аналогично модификатору layout , measurables — это список дочерних элементов, которые необходимо измерить, а constraints — это ограничения от родительского элемента. Следуя той же логике, что и раньше, MyBasicColumn можно реализовать следующим образом:
@Composable fun MyBasicColumn( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( modifier = modifier, content = content ) { measurables, constraints -> // Don't constrain child views further, measure them with given constraints // List of measured children val placeables = measurables.map { measurable -> // Measure each children measurable.measure(constraints) } // Set the size of the layout as big as it can layout(constraints.maxWidth, constraints.maxHeight) { // Track the y co-ord we have placed children up to var yPosition = 0 // Place children in the parent layout placeables.forEach { placeable -> // Position item on the screen placeable.placeRelative(x = 0, y = yPosition) // Record the y co-ord placed up to yPosition += placeable.height } } } }
Дочерние элементы, являющиеся составными, ограничены параметрами Layout (без ограничений minHeight ) и размещаются на основе yPosition предыдущего элемента.
Вот как будет использоваться этот пользовательский составной объект:
@Composable fun CallingComposable(modifier: Modifier = Modifier) { MyBasicColumn(modifier.padding(8.dp)) { Text("MyBasicColumn") Text("places items") Text("vertically.") Text("We've done it by hand!") } }

Column .Направление компоновки
Измените направление компоновки составного элемента, изменив локальную переменную композиции LocalLayoutDirection .
Если вы размещаете элементы компоновки вручную на экране, параметр LayoutDirection является частью LayoutScope модификатора layout или элемента компоновки Layout .
При использовании layoutDirection размещайте компонуемые элементы с помощью place . В отличие от метода placeRelative , place не меняется в зависимости от направления компоновки (слева направо или справа налево).
Настраиваемые макеты в действии
Узнайте больше о макетах и модификаторах в разделе «Базовые макеты» в Compose , а также посмотрите, как работают пользовательские макеты, в примерах Compose, демонстрирующих их создание .
Узнать больше
Чтобы узнать больше о пользовательских макетах в Compose, обратитесь к следующим дополнительным ресурсам.
Видео
{% verbatim %}Рекомендуем вам
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Внутренние измерения в компоновке Compose
- Графика в композиции
- Составьте модификаторы