ConstraintLayout
— это макет, который позволяет размещать составные объекты относительно других составных объектов на экране. Это альтернатива использованию нескольких вложенных Row
, Column
, Box
и других пользовательских элементов макета . ConstraintLayout
полезен при реализации более крупных макетов с более сложными требованиями к выравниванию.
Рассмотрите возможность использования ConstraintLayout
в следующих сценариях:
- Чтобы избежать вложения нескольких
Column
иRow
для позиционирования элементов на экране, чтобы улучшить читаемость кода. - Располагать составные объекты относительно других составных объектов или размещать составные объекты на основе указаний, барьеров или цепочек.
В системе представлений ConstraintLayout
был рекомендуемым способом создания больших и сложных макетов, поскольку плоская иерархия представлений была более производительной, чем вложенные представления. Однако это не проблема в Compose, который способен эффективно обрабатывать глубокие иерархии макетов.
Начало работы с ConstraintLayout
Чтобы использовать ConstraintLayout
в Compose, вам необходимо добавить эту зависимость в свой build.gradle
(в дополнение к настройке Compose ):
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
ConstraintLayout
в Compose работает следующим образом с использованием DSL :
- Создайте ссылки для каждого компонуемого объекта в
ConstraintLayout
, используяcreateRefs()
илиcreateRefFor()
- Ограничения предоставляются с помощью модификатора
constrainAs()
, который принимает ссылку в качестве параметра и позволяет указать ее ограничения в лямбда-выражении тела. - Ограничения задаются с помощью
linkTo()
или других полезных методов. -
parent
— это существующая ссылка, которую можно использовать для указания ограничений для самого составного объектаConstraintLayout
.
Вот пример компоновки с использованием ConstraintLayout
:
@Composable fun ConstraintLayoutContent() { ConstraintLayout { // Create references for the composables to constrain val (button, text) = createRefs() Button( onClick = { /* Do something */ }, // Assign reference "button" to the Button composable // and constrain it to the top of the ConstraintLayout modifier = Modifier.constrainAs(button) { top.linkTo(parent.top, margin = 16.dp) } ) { Text("Button") } // Assign reference "text" to the Text composable // and constrain it to the bottom of the Button composable Text( "Text", Modifier.constrainAs(text) { top.linkTo(button.bottom, margin = 16.dp) } ) } }
Этот код ограничивает верхнюю часть Button
родительским элементом с помощью поля 16.dp
, а Text
— нижней частью Button
также с полем 16.dp
Разделенный API
В примере ConstraintLayout
ограничения указываются в строке с модификатором в составном объекте, к которому они применяются. Однако бывают ситуации, когда предпочтительнее отделить ограничения от макетов, к которым они применяются. Например, вы можете захотеть изменить ограничения на основе конфигурации экрана или выполнить анимацию между двумя наборами ограничений.
В подобных случаях вы можете использовать ConstraintLayout
по-другому:
- Передайте
ConstraintSet
в качестве параметраConstraintLayout
. - Назначьте ссылки, созданные в
ConstraintSet
, составным объектам с помощью модификатораlayoutId
.
@Composable fun DecoupledConstraintLayout() { BoxWithConstraints { val constraints = if (minWidth < 600.dp) { decoupledConstraints(margin = 16.dp) // Portrait constraints } else { decoupledConstraints(margin = 32.dp) // Landscape constraints } ConstraintLayout(constraints) { Button( onClick = { /* Do something */ }, modifier = Modifier.layoutId("button") ) { Text("Button") } Text("Text", Modifier.layoutId("text")) } } } private fun decoupledConstraints(margin: Dp): ConstraintSet { return ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") constrain(button) { top.linkTo(parent.top, margin = margin) } constrain(text) { top.linkTo(button.bottom, margin) } } }
Затем, когда вам нужно изменить ограничения, вы можете просто передать другой ConstraintSet
.
Концепции ConstraintLayout
ConstraintLayout
содержит такие понятия, как рекомендации, барьеры и цепочки, которые могут помочь в позиционировании элементов внутри вашего Composable.
Рекомендации
Рекомендации — это небольшие визуальные помощники при разработке макетов. Составные элементы могут быть ограничены ориентиром. Рекомендации полезны для позиционирования элементов на определенном dp
или percentage
внутри родительского составного объекта.
Существует два разных типа направляющих : вертикальные и горизонтальные. Две горизонтальные — это top
и bottom
, а две вертикальные — start
и end
.
ConstraintLayout { // Create guideline from the start of the parent at 10% the width of the Composable val startGuideline = createGuidelineFromStart(0.1f) // Create guideline from the end of the parent at 10% the width of the Composable val endGuideline = createGuidelineFromEnd(0.1f) // Create guideline from 16 dp from the top of the parent val topGuideline = createGuidelineFromTop(16.dp) // Create guideline from 16 dp from the bottom of the parent val bottomGuideline = createGuidelineFromBottom(16.dp) }
Чтобы создать направляющую, используйте createGuidelineFrom*
с указанием требуемого типа направляющей. При этом создается ссылка, которую можно использовать в блоке Modifier.constrainAs()
.
Барьеры
Барьеры ссылаются на несколько компонуемых объектов для создания виртуальной направляющей на основе самого экстремального виджета на указанной стороне.
Чтобы создать барьер, используйте createTopBarrier()
(или: createBottomBarrier()
, createEndBarrier()
, createStartBarrier()
) и укажите ссылки, которые должны составить барьер.
ConstraintLayout { val constraintSet = ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") val topBarrier = createTopBarrier(button, text) } }
Затем барьер можно использовать в блоке Modifier.constrainAs()
.
Цепи
Цепочки обеспечивают групповое поведение по одной оси (по горизонтали или вертикали). Другая ось может быть ограничена независимо.
Чтобы создать цепочку, используйте createVerticalChain
или createHorizontalChain
:
ConstraintLayout { val constraintSet = ConstraintSet { val button = createRefFor("button") val text = createRefFor("text") val verticalChain = createVerticalChain(button, text, chainStyle = ChainStyle.Spread) val horizontalChain = createHorizontalChain(button, text) } }
Затем цепочку можно использовать в блоке Modifier.constrainAs()
.
Цепочку можно настроить с помощью различных ChainStyles
, которые определяют, как обращаться с пространством, окружающим компонуемый объект, например:
-
ChainStyle.Spread
: пространство распределяется равномерно по всем составным объектам, включая свободное пространство до первого составного объекта и после последнего составного объекта. -
ChainStyle.SpreadInside
: пространство распределяется равномерно по всем составным объектам, без какого-либо свободного места перед первым составным объектом или после последнего составного объекта. -
ChainStyle.Packed
: пространство распределяется перед первым и после последнего составного объекта, составные элементы упаковываются вместе без промежутков между собой.
Узнать больше
Узнайте больше о ConstraintLayout
в Compose из действующих API в примерах Compose, использующих ConstraintLayout
.
Рекомендуется для вас
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Фокус в создании
- Котлин для Jetpack Compose
- Основы составления макета