一、前言
如果我们有布局比较复杂同时对对齐要求很高,那么免不了要嵌套很多Column、Row。虽说对于Compose来说嵌套并不影响性能,但是过多的嵌套却导致较差的可读性和维护性。因此Google退出constraintlayout-compose来解决这个问题,不过目前这个还没有正式版本,所以使用的时候需要注意下API是否已经变更的问题。由于每一种控件、布局的使用方式都有很多api,所以这一系列文章只做最简单的演示
二、相关依赖
constraintlayout-compose需要额外引入,目前最新的版本是
implementation "androidx.constraintlayout:constraintlayout-compose:1.0.0-alpha08"
这个版本需要跟kotlin和compose的编译版本保持一致,如下:
注意其它的compose依赖版本需要和该版本保持一致
composeOptions {
kotlinCompilerExtensionVersion '1.0.0-rc01'
//这个版本必须写,否则使用的kotlin版本可能不是这个版本。就会编译失败
kotlinCompilerVersion "1.5.10"
}
三、示例代码
@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)
})
}
}
四、约束分离createRefFor
在上面的例子中,约束和布局包含在了一起。在布局变得复杂的时候会难以维护,因此可以使用layoutId的方式来进行约束布局
代码源于 https://developer.android.google.cn/jetpack/compose/layouts/constraintlayout?hl=zh-cn
以下主要由两步完成:
- 将
ConstraintSet
作为参数传递给ConstraintLayout
。 - 使用
layoutId
修饰符将在ConstraintSet
中创建的引用分配给可组合项。
然后,当您需要更改约束条件时,只需传递不同的 ConstraintSet
即可。
对于Compose来说,由控件组成页面,任何操作都尽量由控件组成而不牵扯过多的逻辑,跟flutter有点类似
@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)
}
}
}
五、barriers
@Composable
fun ConstraintLayoutContent() {
ConstraintLayout {
// Creates references for the three composables
// in the ConstraintLayout's body
val (button1, button2, text) = createRefs()
Button(
onClick = { /* Do something */ },
modifier = Modifier.constrainAs(button1) {
top.linkTo(parent.top, margin = 16.dp)
}
) {
Text("Button 1")
}
Text("Text", Modifier.constrainAs(text) {
top.linkTo(button1.bottom, margin = 16.dp)
centerAround(button1.end)
})
val barrier = createEndBarrier(button1, text)
Button(
onClick = { /* Do something */ },
modifier = Modifier.constrainAs(button2) {
top.linkTo(parent.top, margin = 16.dp)
start.linkTo(barrier)
}
) {
Text("Button 2")
}
}
}
六、guidelines
@Composable
fun LargeConstraintLayout() {
ConstraintLayout {
val text = createRef()
val guideline = createGuidelineFromStart(fraction = 0.5f)
Text(
"This is a very very very very very very very long text",
Modifier.constrainAs(text) {
linkTo(start = guideline, end = parent.end)
width = Dimension.preferredWrapContent
}
)
}
}
七、chains
chains的用法和在xml中的用法基本上一样
@Composable
fun constrainLayoutChain(){
ConstraintLayout(modifier = Modifier.fillMaxWidth().background(color = Color.Cyan)) {
// Create references for the composables to constrain
val (button, text) = createRefs()
createHorizontalChain(button,text,chainStyle = ChainStyle.Spread) //只需要这一行就可以了
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)
bottom.linkTo(parent.bottom,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) {
centerVerticallyTo(parent)//在剩余空间中垂直居中
})
}
}
八、Group
暂时没有找到相关文档和api
九、参考链接
-
ConstraintLayout的演示:
https://developer.android.google.cn/jetpack/compose/layout#responsive-layouts
-
Compose 中的 ConstraintLayout
https://developer.android.google.cn/jetpack/compose/layouts/constraintlayout?hl=zh-cn
-
Compose的codelabs资源
https://developer.android.google.cn/codelabs/jetpack-compose-layouts#9
-
compose-samples
-
Compose ConstraintLayout 详讲
https://blog.csdn.net/cym492224103/article/details/114314776