D04 / 可不可以用 ConstraintLayout - ConstraintLayout

今天大概会聊到的范围

  • Constraint Layout in Compose

上一篇提到,有 Row / Column 和 Box,配合各种 alignment 的方式,就可以排出各种画面。事实上,原先的 Android 画面也是如此,透过 horizontal 和 vertical 的 LinearLayout 就可以排出各种画面。

但没多久,大家就发现问题了。画面的设计越来越复杂,越来越多层的 Layout 需要被互相嵌套,进而导致了效能问题。最後,为了摊平 view 的层数,RelativeLayout 和 ConstraintLayout 产生并被推荐变成画画面时的固定班底。

在 Compose 中,因为运算 layout 大小的路线不同,嵌套多层 Composable 并不会造成过多的运算压力,因此大家可以更放心的透过 Row / Column 这类基本的 Layout 进行布局。

但 ConstraintLayout 还是很有帮助的。透过描述 item 与 item 之间的关联,让这个 View  可以自适应各种内容与大小,有时是非常方便的。

所以,要如何在 Compose 中使用 ConstraintLayout 呢?

导入 library

implementation "androidx.constraintlayout:constraintlayout-compose:$constraint_version"

ConstraintLayout 并不在 Compose 的 library 中,版本也是跟着 constraint layout 的版本。在使用之前要另外导入。

产生 ConstraintRef

和 XML 不同,在 Compose 中每个 component 必没有 id 。因此,在形容 component 间的关系之前,必须得先替每个 component "命名"。

ConstraintLayout() {
    // 建立用来做关联的 "id/ref"
    val (titleRef, coverArtRef, blockSpaceRef) = createRefs()     
}

透过 createRefs() 这个 funciton, 可以产出多个 "ref",功能和 XML 中的 id 类似。透过 destructuring 的方式可以一次定义出多个 ref。

描述 Constraint

接下来,在 ConstraintLayout 中的 Composable 的会多一个 constraintAs 的 Modifier 用来描述 constraint。用 constraintAs  时需要提供一个稍早产生出来的 ref,并且提供一个 Lambda,在 lambda 中描述这个 component 与其他 component 的关系。

Text(
    text = "Text",
    modifier = Modifier.constrainAs(titleRef) {  // 使用 Modifier.constrainAs 定义每个元件的 id
        // 在这里定义这个元件与其他元件的关联 (constraint)
        // parent 是内建的
        top.linkTo(parent.top, margin = 8.dp)
        start.linkTo(parent.start, margin = 8.dp)
    }
)

在描述时,可以透过 <top|bottom|start|end>.linkTo(<ref>.<top|bottom|start|end>) 的语法描述物件与物间之间的关系。

另外,也可以直接使用 linkTo 这个 function 一次描述垂直、水平或四周的 constraint

Spacer(modifier = Modifier
    .constrainAs(blockSpaceRef) {
        // linkTo function 可以一次定义多个 constraint
        linkTo(top = parent.top, bottom = parent.bottom)
    })

如此,就可以和使用熟悉的 ConstraintLayout 逻辑,来建构画面了

@Preview(
    heightDp = 80,
    widthDp = 160
)
@Composable
fun `Preview Constraint`(){
    ConstraintLayout(
        modifier = Modifier
            .clip(RoundedCornerShape(8.dp))
            .background(color = backgroundColor)
    ) {
        // 建立用来做关联的 "id"
        val (titleRef, coverArtRef, blockSpaceRef) = createRefs()
        
        
        Text(
            text = "Talking",
            // 使用 Modifier.constrainAs 定义每个元件的 id
            modifier = Modifier.constrainAs(titleRef) {
                // 在这里定义这个元件与其他元件的关联 (constraint)
                // parent 是内建的
                top.linkTo(parent.top, margin = 8.dp)
                start.linkTo(parent.start, margin = 8.dp)
            },
            color = Color.White, fontWeight = FontWeight.Black
        )
        
        Spacer(modifier = Modifier
            .constrainAs(blockSpaceRef) {
                // linkTo function 可以一次定义多个 constraint
                linkTo(top = parent.top, bottom = parent.bottom)
            }
            .defaultMinSize(minHeight = 100.dp))
        
        Image(
            painter = painterResource(id = image),
            contentDescription = null,
            modifier = Modifier
                .constrainAs(coverArtRef) {
                    bottom.linkTo(parent.bottom)
                    end.linkTo(parent.end, margin = (-10).dp)
                }
                .height(60.dp)
                .width(60.dp)
                .rotate(30f)
        )
        
    }
    
}

https://ithelp.ithome.com.tw/upload/images/20210918/201415970fbBiLmtok.png


实际使用起来,发现 ConstraintLayout 在 Compose 的结构下依然简单易懂。很适合在画面关系复杂时使用。但仍要再次提醒,在 Compose 的结构下,ConstraintLayout 不再是因为效能的选择。在其他平台使用 Compose 时也不支援。但当画面关系复杂,不适合用简易的 Row / Column 描述时,ConstraintLayout 会是个增加程序可读性的好帮手。

Reference:


<<:  Re: 新手让网页 act 起来: Day03 - 再次了解React.createElement()

>>:  认识HTML(一)

软件开发团队 “有动力自主成长” 的 LOC 100K 门槛

在一般的软件公司,和面对规模的不大的专案,除非你是个对软件开发、工程品质、效率 “真的” 有兴趣,而...

截取Video画面,存成一张张图片Python cv2

找到一个有趣的程序码,改了一下,可截取Video画面,存成一张张图片。 进行中想要中断执行,可按 E...

[Day11]C# 鸡础观念- 把复杂的事情与关系简单化~列举与结构

在电脑世界中,很多编码都是复杂且看不懂的, 例如颜色编码,FF0000代表红色,800080代表绿色...

Day.10 Stack

Stack(堆叠)是一种後进先出(LIFO)的资料结构 看一下图 注:图源 你可以想像一下在厨房洗碗...

图的最小产生树 - DAY 26

普林演算法 紫色为可以选择的路线,绿色为走的路线 找可选择的最小值路线去走,就可以完成 克鲁斯克尔演...