ConstraintLayout 是一个布局,允许您在屏幕上将可组合项相对于其他可组合项放置。它替代了使用多个嵌套的 Row、Column、Box 和其他自定义布局元素。ConstraintLayout 在实现具有更复杂对齐要求的大型布局时非常有用。
在以下场景中考虑使用 ConstraintLayout:
- 避免嵌套多个
Column和Row来定位屏幕上的元素,以提高代码可读性。 - 将可组合项相对于其他可组合项进行定位,或根据参考线、屏障或链条定位可组合项。
在 View 系统中,ConstraintLayout 是创建大型复杂布局的推荐方式,因为扁平的视图层次结构比嵌套视图对性能更有利。然而,这在 Compose 中不是问题,因为 Compose 能够高效地处理深度布局层次结构。
开始使用 ConstraintLayout
要在 Compose 中使用 ConstraintLayout,您需要在 build.gradle 中添加此依赖项(除了Compose 设置外):
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.1"
Compose 中的 ConstraintLayout 通过DSL 以以下方式工作:
- 使用
createRefs()或createRefFor()为ConstraintLayout中的每个可组合项创建引用。 - 约束通过
constrainAs()修饰符提供,该修饰符以引用作为参数,并允许您在其主体 lambda 中指定约束。 - 约束通过
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。 - 使用
layoutId修饰符将ConstraintSet中创建的引用分配给可组合项。
@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() 块中使用链条。
链条可以使用不同的 ChainStyle 进行配置,这些样式决定如何处理可组合项周围的空间,例如:
ChainStyle.Spread:空间均匀分布在所有可组合项之间,包括第一个可组合项之前和最后一个可组合项之后的自由空间。ChainStyle.SpreadInside:空间均匀分布在所有可组合项之间,第一个可组合项之前和最后一个可组合项之后没有自由空间。ChainStyle.Packed:空间分布在第一个和最后一个可组合项之前和之后,可组合项紧密排列,彼此之间没有空间。
了解详情
从使用 ConstraintLayout 的 Compose 示例中了解更多关于 Compose 中 ConstraintLayout 的 API 实际应用。
为您推荐
- 注意:当 JavaScript 关闭时,会显示链接文本
- Compose 中的焦点
- Jetpack Compose 版 Kotlin
- Compose 布局基础知识