This article looks at the uses of BoxWithConstraints, Spacer,Divider, Card, and ConstraintLayout.

A: the Spacer

Spacer is actually very simple, is the white space, the role of space. Look at the code

@Composable
fun Spacer(modifier: Modifier) {
    Layout({}, modifier) { _, constraints ->
        with(constraints) {
            val width = if (hasFixedWidth) maxWidth else 0
            val height = if (hasFixedHeight) maxHeight else 0
            layout(width, height) {}
        }
    }
}
Copy the code
  • Modifier Detailed explanation of the use of modifier

For example:

@Preview()
@Composable
fun spacerTest(a){
    Column(modifier = Modifier.fillMaxSize()) {
        Box(modifier = Modifier
            .fillMaxWidth()
            .height(60.dp)
            .background(Color.Red))
        Spacer(modifier = Modifier.height(10.dp))
        Box(modifier = Modifier
            .fillMaxWidth()
            .height(60.dp)
            .background(Color.Red))
    }
}
Copy the code

2: Divider

Dividers serve as dividing lines. Look at the code

@Composable
fun Divider(
    modifier: Modifier = Modifier,
    color: Color = MaterialTheme.colors.onSurface.copy(alpha = DividerAlpha),
    thickness: Dp = 1.dp,
    startIndent: Dp = 0.dp
)
Copy the code
  • Modifier Detailed explanation of the use of modifier
  • Color color
  • Thickness line height
  • StartIndent The spacing at the beginning of the distance is similar to marginStart

For example:

@Preview()
@Composable
fun drivertest(a){
    Column(modifier = Modifier.fillMaxSize()) {
        Box(modifier = Modifier
            .fillMaxWidth()
            .height(60.dp)
            .background(Color.Red))
        Divider(
            modifier = Modifier.fillMaxWidth().height(1.dp),
            color = Color.Black,
            startIndent = 10.dp
        )
        Box(modifier = Modifier
            .fillMaxWidth()
            .height(60.dp)
            .background(Color.Red))
    }
}
Copy the code

Three: BoxWithConstraints

To understand the constraints from the parent and design the layout accordingly, you can use BoxWithConstraints. For example, if the parent gives us a maximum width of 100.dp, then when we use BoxWithConstraints to layout the child View, for example, the child View is 30.dp wide, we can determine that only the next three views can be displayed in a row. Let’s look at the code:

@Composable
fun BoxWithConstraints(
    modifier: Modifier = Modifier,
    contentAlignment: Alignment = Alignment.TopStart,
    propagateMinConstraints: Boolean = false,
    content: @Composable BoxWithConstraintsScope. () - >Unit
){... }Copy the code
  • Modifier Detailed explanation of the use of modifier
  • ContentAlignment indicates the contentAlignment
  • PropagateMinConstraints specifies whether a constraint is applied to a child View
  • The content content

For example:

@Preview()
@Composable
fun boxWithConstraintsTest(a){
    BoxWithConstraints(
        modifier = Modifier.fillMaxWidth(),
        contentAlignment = Alignment.TopStart,
        propagateMinConstraints = true,
    ){
        val itemW = 50.dp
        val spaceW = 2.dp
        val count = (maxWidth.value/(itemW.value+spaceW.value)).toInt()
        if (count>0) {
            Row() {
                for(i in 0 until count){
                    Box(Modifier.size(50.dp, 50.dp).background(Color.Blue))
                    Spacer(Modifier.size(2.dp))
                }
            }
        }
    }
}
Copy the code

Four: Card

Card, let’s look at the code

@Composable
fun Card(
    modifier: Modifier = Modifier,
    shape: Shape = MaterialTheme.shapes.medium,
    backgroundColor: Color = MaterialTheme.colors.surface,
    contentColor: Color = contentColorFor(backgroundColor),
    border: BorderStroke? = null,
    elevation: Dp = 1.dp,
    content: @Composable() - >Unit
) {
    Surface(
        modifier = modifier,
        shape = shape,
        color = backgroundColor,
        contentColor = contentColor,
        elevation = elevation,
        border = border,
        content = content
    )
}
Copy the code
  • Modifier modifier
  • Shape shape
  • BackgroundColor backgroundColor
  • ContentColor Specifies the color of the content
  • Border border
  • Elevation shadow
  • The content content

For example:

@Preview()
@Composable
fun cardTest(a){
    Card(
        modifier = Modifier.size(200.dp).padding(10.dp),
        shape = RoundedCornerShape(8.dp),
        backgroundColor = Color.White,
        contentColor = Color.Black,
        border = BorderStroke(0.5.dp, Color.Gray),
        elevation = 10.dp
    ) {
        Column() {
            Image(painter = painterResource(id = R.drawable.icon_head), contentDescription = "Image",contentScale = ContentScale.FillBounds)
        }
    }
}
Copy the code

Five: ConstraintLayout

ConstraintLayout is recommended for creating large, complex layouts in View systems, because it can effectively reduce the layout level to optimize performance. However, this is in Compose because it can efficiently handle deeper layout hierarchies. So it’s better to use Cloumn with Row. ConstraintLayout is useful, however, when implementing larger layouts with more complex alignment requirements. To use ConstraintLayout in Compose, you need to add the following dependencies to build.gradle:

implementation "Androidx. Constraintlayout: constraintlayout - compose: 1.0.0 - alpha05"
Copy the code
  • Create an associated reference through createRefs() or createRefFor().
  • Use the constraint provided by the constrainAs() modifier.
  • Constraints are specified using linkTo() or some other useful method.
  • Parent is an existing reference that can be used to specify constraints on the ConstraintLayout combinable item itself.

The top of the button is 16dp away from the top of the parent button and the top of the text button is 16dp away from the bottom of the button

@Preview()
@Composable
fun constraintTest(a){
    ConstraintLayout() {
        val(button,text) = createRefs()
        Button(
            onClick = { /*TODO*/ },
            modifier = Modifier.constrainAs(button){
                top.linkTo(parent.top,margin = 16.dp)
            }
        ) {
            Text("Button")
        }
        
        Text("Text", Modifier.constrainAs(text) {
            top.linkTo(button.bottom, margin = 16.dp)
        })
    }
}
Copy the code

Let’s look at the code for ConstraintLayout

ConstraintLayout(
 modifier: Modifier,
 optimizationLevel:Int, 
 content: @Composable(ConstraintLayoutScope.() -> Unit) {... } ConstraintLayout( constraintSet: ConstraintSet, modifier: Modifier, optimizationLevel:Int, 
 content: @Composable(ConstraintLayoutScope.() -> Unit) {... }Copy the code
  • ConstraintSet constraints
  • OptimizationLevel level
  • Modifier modifier
  • The content content

In the example above, the constraints are specified in ConstraintLayout. In some cases, however, it is best to separate the constraints from the layout to which they are applied. For example, you might want to change constraints based on screen configuration, or add animation effects between two sets of constraints. In this case, you can use ConstraintLayout in different ways:

  • ConstraintSet is passed to ConstraintLayout as an argument.
  • Assign a reference created in ConstraintSet to a composable item using the layoutId modifier.
@Preview()
@Composable
fun constraintTest(a) {
    ConstraintLayout(
        optimizationLevel = 1,
        constraintSet = decoupledConstraints(12.dp)
    ) {
        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 = margin)
        }
    }
}
Copy the code

See the layout in Compose