Constraint layout of Android jetpack Compose

overview

We all know that ConstraintLayout can effectively reduce the height of the view tree and flatten the view tree when building a nested and complex view interface. Constraint layout has better performance in measuring layout time than traditional relative layout, and constraint layout Terminal devices of various sizes can be adapted according to the percentage. Because the constraint layout is really easy to use, the official also migrated the constraint layout to the Compose platform for us. This article is to introduce the use of constraint layout in Compose.

Example analysis

Before using the constraint layout, we need to add the compose version of the ConstraintLayout dependency to the app.gradle script in the project

implementation('androidx.constraintlayout:constraintlayout-compose:1.0.1')

After introducing dependencies, we can see how to use constraint layout in Compose

1. Create references

In the traditional View system, we can set the resource ID for the View in the layout XML file, and use the resource ID as an index to declare the placement position of the corresponding component. In Compose's constraint layout, you can actively create references and bind them to a specific component to achieve a function similar to resource IDs. Each component can use the references of other components to obtain the placement information of other components. , so as to determine their own placement.

There are two ways for Compose to create a constraint layout, namely createRef() and createRefs(). According to the literal meaning, we can clearly know that createRef() will only create one reference each time, while createRefs() can Create multiple references (up to 16), the way to create a reference is as follows:

// 创建单个引用
 val text = createRef()
// 创建多个引用
 val (button1,button2,text) = createRefs()

2. Bind references

After we create the reference, we can use the Modifier.constrainAs() modifier to bind the reference we created to a specific component, and we can specify the constraint information of the component in the Lambda at the end of contrainAs. We need to note that we can only use createRefer and createRefs functions in the Lambda at the end of ConstraintLayout to create references, and use the Modifier.constrainAs function to bind references, because the Reciever of Lambda at the end of ConstraintScope is a ConstraintLayoutScope scope object. We can first look at the following piece of code to understand the reference binding of the constraint layout:

@Composable
fun ConstrainLayoutDemo()
{
    
    
    ConstraintLayout(modifier = Modifier
        .width(300.dp)
        .height(100.dp)
        .padding(5.dp)
        .border(5.dp, color = Color.Red)) {
    
    
        val portraitImageRef = remember {
    
    
            createRef()
        }

        Image(painter = painterResource(id = R.drawable.portrait)
            , contentDescription = null,
        modifier = Modifier.constrainAs(portraitImageRef){
    
    
            top.linkTo(parent.top)
            bottom.linkTo(parent.bottom)
            start.linkTo(parent.start)
        })

    }
}

operation result:
insert image description here

The above code is part of the code to implement a user card. From the code, we can see that we need to use Modifier.constrainsAs(){...} when using constraints. The tail Lambda of Modifier.constrainsAs is a ConstrainScope scope object, in which information such as parent, top, bottom, start, and end of the current component can be obtained. And use linkTo to specify component constraints. In the above interface, we hope that the user's avatar can be aligned to the left, so top is stretched to the top of the parent component, bottom is stretched to the bottom of the parent component, and start is stretched to the left of the parent component. Let's add the user's nickname and description to the card. The entire code is as follows:

@Composable
fun ConstrainLayoutDemo()
{
    
    
    ConstraintLayout(modifier = Modifier
        .width(300.dp)
        .height(100.dp)
        .padding(5.dp)
        .border(5.dp, color = Color.Red)) {
    
    
        val (portraitImageRef,usernameTextRef,descriptionTextRef) = remember {
    
    
            createRefs()
        }

        Image(painter = painterResource(id = R.drawable.portrait)
            , contentDescription = null,
        modifier = Modifier.constrainAs(portraitImageRef){
    
    
            top.linkTo(parent.top)
            bottom.linkTo(parent.bottom)
            start.linkTo(parent.start)
        })

        Text(text = "旅游小美女", fontSize = 16.sp, maxLines = 1,
        textAlign = TextAlign.Left,
        modifier = Modifier.constrainAs(usernameTextRef){
    
    
            top.linkTo(portraitImageRef.top)
            start.linkTo(portraitImageRef.end,10.dp)
        })

        Text(text = "个人描述。。。。。。。。", fontSize = 14.sp,
            color = Color.Gray,
            fontWeight = FontWeight.Light,
            modifier = Modifier.constrainAs(descriptionTextRef){
    
    
                top.linkTo(usernameTextRef.bottom,5.dp)
                start.linkTo(portraitImageRef.end,10.dp)
            }
        )
    }
}

Running result:
insert image description here
In the above code, we can also specify the width and height information of the component in ConstrainScope, and directly set the optional values ​​of width and height in ConstrainScope as follows:

When specifying the width and height information of a component in ConstrainScope, Modifier.constrainAs(xxxRef){width = Dimension.可选值}set it in , and the optional values ​​are as follows:
Dimension.wrapContent: The actual size is adaptive according to the content
Dimension.matchParent: The actual size is the size that covers the parent component
Dimension, wrapContent: Actual The size is the size stretched according to the constraint information
Dimension.preferredWrapContent: If the remaining space is larger than the more content-adaptive size, the actual size is the adaptive size; if the remaining space is smaller than the content-adaptive size, the actual size is the remaining space Dimension.ratio
(String): Calculate the ratio of actual size based on string: such as 1:2
Dimension.percent(Float): Calculate the ratio of actual size based on floating point number
Dimension.value(Dp): Set the size to be fixed Value
Dimension.perferredValue(Dp): If the remaining space is greater than a fixed value, the actual size is a fixed value; if the remaining space is smaller than a fixed value, the actual size is the remaining space size

Let's imagine that if the user's nickname is very long, then according to our above code display, there will be incomplete display, so we can specify the endmaximum width allowed by the component by setting, and set the width to preferredWrapContent, which means when the user When the name is very long, the actual width will be adjusted adaptively. Let's change the place where the user name is displayed above, the code is as follows:

// 上面的代码只用改这个部分
   Text(
            text = "旅游小美女美美美美美名字很长长长长长长长长长",
            fontSize = 16.sp,
        textAlign = TextAlign.Left,
        modifier = Modifier.constrainAs(usernameTextRef){
    
    
            top.linkTo(portraitImageRef.top)
            start.linkTo(portraitImageRef.end,10.dp)
            end.linkTo(parent.end,10.dp)
            width = Dimension.preferredWrapContent
        })

operation result:
insert image description here

Auxiliary layout tool

In the constraint layout of traditional View, there are auxiliary layout tools such as Barrier and GuideLine, and these features are also inherited in Compose, which is convenient for us to complete the layout requirements of various complex scenes.

1. Barrier dividing line

As the name suggests, Barrier is a barrier, which can be used to isolate some mutual extrusion effects on the UI layout. For example, we want two input boxes to be left-aligned, and the distance from the longest text component is still 10dp When the user name and password change, the position of the input box can be adjusted adaptively. Here, using the Barrier feature can easily achieve this requirement:

@Composable
fun InputFieldLayout(){
    
    
    ConstraintLayout(
        modifier = Modifier
            .width(400.dp)
            .padding(10.dp)
    ) {
    
    
        val (usernameTextRef, passwordTextRef, usernameInputRef, passWordInputRef) = remember {
    
     createRefs() }
        val barrier = createEndBarrier(usernameTextRef, passwordTextRef)
        Text(
            text = "用户名",
            fontSize = 14.sp,
            textAlign = TextAlign.Left,
            modifier = Modifier
                .constrainAs(usernameTextRef) {
    
    
                    top.linkTo(parent.top)
                    start.linkTo(parent.start)
                }
        )

        Text(
            text = "密码",
            fontSize = 14.sp,
            modifier = Modifier
                .constrainAs(passwordTextRef) {
    
    
                    top.linkTo(usernameTextRef.bottom, 20.dp)
                    start.linkTo(parent.start)
                }
        )
        OutlinedTextField(
            value = "",
            onValueChange = {
    
    },
            modifier = Modifier.constrainAs(usernameInputRef) {
    
    
                start.linkTo(barrier, 10.dp)
                top.linkTo(usernameTextRef.top)
                bottom.linkTo(usernameTextRef.bottom)
                height = Dimension.fillToConstraints
            }
        )
        OutlinedTextField(
            value = "",
            onValueChange = {
    
    },
            modifier = Modifier.constrainAs(passWordInputRef) {
    
    
                start.linkTo(barrier, 10.dp)
                top.linkTo(passwordTextRef.top)
                bottom.linkTo(passwordTextRef.bottom)
                height = Dimension.fillToConstraints
            }
        )
    }
}

operation result:
insert image description here

2.Guideline guide line

The Barrier boundary needs to rely on other references to determine its own position, while using Guideline does not depend on any references. For example, we want to place the user's avatar at a height of 2:8 from the top of the screen. Above the avatar is the user's background. The following is User information, such requirements can be implemented using Guideline, the code is as follows:

@Composable
fun GuidelineDemo(){
    
    
   ConstraintLayout(modifier = Modifier
       .height(300.dp)
       .background(color = Color.Gray)) {
    
    
       val guideline = createGuidelineFromTop(0.2f)
       val (userPortraitBackgroundRef,userPortraitImgRef,welcomeRef) = remember {
    
    
           createRefs()
       }

       Box(modifier = Modifier
           .constrainAs(userPortraitBackgroundRef) {
    
    
               top.linkTo(parent.top)
               bottom.linkTo(guideline)
               height = Dimension.fillToConstraints
               width = Dimension.matchParent
           }
           .background(Color(0xFF673AB7)))

       Image(painter = painterResource(id = R.drawable.portrait),
           contentDescription = null,
           modifier = Modifier
               .constrainAs(userPortraitImgRef) {
    
    
                   top.linkTo(guideline)
                   bottom.linkTo(guideline)
                   start.linkTo(parent.start)
                   end.linkTo(parent.end)
               }
               .size(100.dp)
               .clip(CircleShape)
               .border(width = 2.dp, color = Color(0xFF96659E), shape = CircleShape))

       Text(text = "不喝奶茶的小白兔",
       color = Color.White,
       fontSize = 26.sp,
       modifier = Modifier.constrainAs(welcomeRef){
    
    
           top.linkTo(userPortraitImgRef.bottom,10.dp)
           start.linkTo(parent.start)
           end.linkTo(parent.end)
       })

   }
}

operation result:
insert image description here

In the above code, we use the createGuidelineFromTop() method to create a guideline starting from the top, then the user background can rely on this guideline to determine the width and height, and then for the avatar, we only need to connect top and bottom to guide line

3. Chain link constraints

Another useful feature of ContraintLayout is Chain link constraints, which allow multiple components to evenly allocate layout space through link constraints, similar to weight modifiers. For example, if we want to display an ancient poem, we can implement it with Chain link constraints as follows:

@Composable
fun showQuotesDemo() {
    
    
    ConstraintLayout(
        modifier = Modifier
            .size(400.dp)
            .background(Color.Black)
    ) {
    
    
        val (quotesFirstLineRef, quotesSecondLineRef, quotesThirdLineRef, quotesForthLineRef) = remember {
    
    
            createRefs()
        }

        createVerticalChain(
            quotesFirstLineRef, quotesSecondLineRef, quotesThirdLineRef, quotesForthLineRef,
            chainStyle = ChainStyle.Spread
        )

        Text(text = "窗前明月光,",
            color = Color.White,
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier.constrainAs(quotesFirstLineRef) {
    
    
                start.linkTo(parent.start)
                end.linkTo(parent.end)
            })

        Text(text = "疑是地上霜。",
            color = Color.White,
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier.constrainAs(quotesSecondLineRef) {
    
    
                start.linkTo(parent.start)
                end.linkTo(parent.end)
            })

        Text(text = "举头望明月,",
            color = Color.White,
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier.constrainAs(quotesThirdLineRef) {
    
    
                start.linkTo(parent.start)
                end.linkTo(parent.end)
            })

        Text(text = "低头思故乡。",
            color = Color.White,
            fontSize = 20.sp,
            fontWeight = FontWeight.Bold,
            modifier = Modifier.constrainAs(quotesForthLineRef) {
    
    
                start.linkTo(parent.start)
                end.linkTo(parent.end)
            })
    }
}

Running result:
insert image description here
As shown in the above code, we need to create four references corresponding to the four lines of poems to display the four lines of poems, and then we can create a vertical link constraint to connect the four lines of poems. When creating a link constraint, the end parameter can be Pass a ChainStyle to represent the layout style we expect. It has three values. The effects and meanings are as follows:

(1) Spread: Each element in the chain equally divides the entire parent space

 createVerticalChain(
            quotesFirstLineRef, quotesSecondLineRef, quotesThirdLineRef, quotesForthLineRef,
            chainStyle = ChainStyle.Spread)

running result:

insert image description here

(2) SpreadInside: The first and last elements in the chain are close to the boundary, and each remaining element equally divides the entire parent space

 createVerticalChain(
            quotesFirstLineRef, quotesSecondLineRef, quotesThirdLineRef, quotesForthLineRef,
            chainStyle = ChainStyle.SpreadInside)

running result:

insert image description here

(3) Packed: All elements in the chain are gathered in the middle, the effect is as follows

 createVerticalChain(
            quotesFirstLineRef, quotesSecondLineRef, quotesThirdLineRef, quotesForthLineRef,
            chainStyle = ChainStyle.Packed)

running result:

insert image description here

Summarize

This is all about the content of Compose constraint layout. This article mainly briefly introduces the basic use of constraint layout in Compose. To master Compose constraint layout, readers need to contact more and use constraint layout to write interface, so that practice makes perfect , here I just do a job of throwing bricks and attracting jade. If you have any questions, please communicate in the comment area.

Guess you like

Origin blog.csdn.net/zxj2589/article/details/130340316