ConstraintLayout — это макет, позволяющий размещать элементы, которые можно комбинировать, относительно других элементов на экране. Он является альтернативой использованию нескольких вложенных элементов Row , Column , Box и других пользовательских элементов макета . ConstraintLayout полезен при реализации больших макетов со сложными требованиями к выравниванию.
Рекомендуется использовать ConstraintLayout в следующих сценариях:
- Чтобы избежать вложенности нескольких
ColumnиRowдля позиционирования элементов на экране и улучшить читаемость кода. - Для позиционирования составных элементов относительно других составных элементов или для позиционирования составных элементов на основе направляющих, барьеров или цепей.
В системе View для создания больших и сложных макетов рекомендовался ConstraintLayout , поскольку плоская иерархия представлений обеспечивала лучшую производительность, чем вложенные представления. Однако в Compose это не является проблемой, поскольку он способен эффективно обрабатывать глубокие иерархии макетов.
Начните работу с ConstraintLayout
Для использования ConstraintLayout в Compose необходимо добавить следующую зависимость в файл build.gradle (в дополнение к настройкам Compose ):
implementation "androidx.constraintlayout:constraintlayout-compose:$constraintlayout_compose_version"
В Compose ConstraintLayout работает следующим образом, используя 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

Button и Text которые можно скомпоновать, будучи связанными друг с другом в ConstraintLayout .Разделенный 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 содержит такие понятия, как направляющие, барьеры и цепочки, которые могут помочь в позиционировании элементов внутри вашего составного элемента.
Руководящие принципы
Направляющие линии — это небольшие визуальные вспомогательные элементы для проектирования макетов. Элементы, являющиеся составными частями, могут быть привязаны к направляющей линии. Направляющие линии полезны для позиционирования элементов на определенном расстоянии 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 .