Compose中的ConstraintLayout布局(三)

一、前言

如果我们有布局比较复杂同时对对齐要求很高,那么免不了要嵌套很多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

以下主要由两步完成:

  1. ConstraintSet 作为参数传递给 ConstraintLayout
  2. 使用 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

九、参考链接

  1. ConstraintLayout的演示:

    https://developer.android.google.cn/jetpack/compose/layout#responsive-layouts

  2. Compose 中的 ConstraintLayout

    https://developer.android.google.cn/jetpack/compose/layouts/constraintlayout?hl=zh-cn

  3. Compose的codelabs资源

    https://developer.android.google.cn/codelabs/jetpack-compose-layouts#9

  4. compose-samples

    https://github.com/android/compose-samples

  5. Compose ConstraintLayout 详讲

    https://blog.csdn.net/cym492224103/article/details/114314776

  6. Android jetpack Compose之约束布局

  7. fillToConstraints和preferredWrapContent

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Compose的副作用是指在Composable的生命周期执行的操作,例如内存缓存、数据库操作、网络请求、文件读取、日志处理、页面跳转等。Compose提供了一些API来处理这些副作用,以确保它们在Composable的特定阶段被执行,从而保证行为的可预期性。 在Compose,副作用可以通过以下方式实现: 1. 使用LaunchedEffect函数:这个函数可以在Composable的生命周期启动一个协程,并在协程完成后自动取消。这样可以执行一些异步操作,例如网络请求或数据库查询。以下是一个使用LaunchedEffect函数的示例: ```kotlin @Composable fun MyComposable() { LaunchedEffect(Unit) { // 执行异步操作,例如网络请求或数据库查询 // ... } } ``` 2. 使用DisposableEffect函数:这个函数可以在Composable的生命周期创建和清理资源。当Composable第一次创建时,会执行创建资源的代码块;当Composable被移除时,会执行清理资源的代码块。以下是一个使用DisposableEffect函数的示例: ```kotlin @Composable fun MyComposable() { DisposableEffect(Unit) { // 创建资源,例如打开文件或建立数据库连接 // ... onDispose { // 清理资源,例如关闭文件或断开数据库连接 // ... } } } ``` 3. 使用SideEffect函数:这个函数可以在Composable的生命周期执行一些副作用操作,例如弹出Toast提醒或记录日志。以下是一个使用SideEffect函数的示例: ```kotlin @Composable fun MyComposable() { SideEffect { // 执行副作用操作,例如弹出Toast提醒或记录日志 // ... } } ``` 这些是Compose处理副作用的常用方法。通过使用这些API,可以确保副作用在Composable的生命周期被正确执行,从而保证行为的可预期性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值