In the last article, we completed the Switch, CheckBox, RadioButton related content learning, so far, the most basic simple control we have learned, next we will learn the basic layout.

Taking Android as an example, we have completed TextView, Edittext, Button, ImageView, CheckBox, SwitchButton, RadioButton and so on.

Next you’ll start learning layout rules, such as FrameLayout, LinearLayout, RelativeLayout, ConstraintLayout, and so on

The code in this article is based on version 1.0.1

Unless otherwise specifiedComposeBoth refer toJetpack compose

All the code in this article is available in WorkShop. This code is concentrated in the Post29 package

A complete series of directory: making Pages | Denver | CSDN

Box

Similar to FrameLayout in Android.

In UI design, it is inevitable that some UI elements will be grouped together to change their overall appearance and “separate” them from the environment. This approach was naturally born: wrap these UI elements in a single node, applying the overall look and feel to that node.

Note: This node has the flexibility to choose a layout based on the requirements of the layout elements — in Compose, the node can be Box, but it doesn’t have to be Box!

use

@Composable
inline fun Box(
    modifier: Modifier = Modifier,
    contentAlignment: Alignment = Alignment.TopStart,
    propagateMinConstraints: Boolean = false,
    content: @Composable BoxScope. () - >Unit
)
Copy the code

Obviously, this is an inline function, which means that it is similar to the Facade pattern, but the underlying implementation is more complex, where the requirements scenario is wrapped and a lot of details are hidden

At this stage of learning, we restrain our curiosity by not exploring details.

Parameter Meanings:

  • The modifier: modifier
  • ContentAlignment: contentAlignmentNote: This is different from FrameLayout
  • 5, propagateMinConstraints: Whether the minimum size is applied to the content. If TRUE, the minimum size of the content is set according to information in the Modifier, otherwise it only applies to Box
  • Content: contentAndroid neutralizes the concept of View

For WorkShop, we used a Demo from Google

Box {
    Box(Modifier.fillMaxSize().background(Color.Cyan))
    Box(
            Modifier.matchParentSize().padding(top = 20.dp, bottom = 20.dp).background(Color.Yellow)
    )
    Box(
            Modifier.matchParentSize().padding(40.dp).background(Color.Magenta)
    )
    Box(
            Modifier.align(Alignment.Center).size(300.dp, 300.dp).background(Color.Green)
    )
    Box(
            Modifier.align(Alignment.TopStart).size(150.dp, 150.dp).background(Color.Red)
    )
    Box(
            Modifier.align(Alignment.BottomEnd).size(150.dp, 150.dp).background(Color.Blue)
    )
}
Copy the code

In this Demo, we can see:

  • The effect of alignment and padding on the position and size of the Box
  • The contents are arranged in the order of declaration

Adjust content to Box layout limits

It’s a fit for different screen sizes

This will use: BoxWithConstraints

@Composable
fun BoxWithConstraints(
    modifier: Modifier = Modifier,
    contentAlignment: Alignment = Alignment.TopStart,
    propagateMinConstraints: Boolean = false,
    content: @Composable BoxWithConstraintsScope. () - >Unit
)
Copy the code

The difference with Box is content. The context in lambda is BoxWithConstraintsScope instance, not BoxScope instance. Therefore, we can know Box’s size limit at layout time:

@Stable
interface BoxWithConstraintsScope : BoxScope {
    /** * The constraints given by the parent layout in pixels. * Use [minWidth], [maxWidth], [minHeight] or [maxHeight] if you need value in [Dp]. */
    val constraints: Constraints
    /** * The minimum width in [Dp]. */
    val minWidth: Dp
    /** * The maximum width in [Dp]. */
    val maxWidth: Dp
    /** * The minimum height in [Dp]. */
    val minHeight: Dp
    /** * The maximum height in [Dp]. */
    val maxHeight: Dp
}
Copy the code

Here is an example:

When the maximum height of the Box is less than 100DP, place a 50* 50DP Box; otherwise, place two boxes vertically; The initial height is 80dp. Click the button to switch back and forth between 100DP and 80DP:

var height by rememberSaveable { mutableStateOf(80) }
BoxWithConstraints(
    modifier = Modifier.height(height.dp)
) {
    val rectangleHeight = 50.dp
    if (maxHeight < rectangleHeight * 2) {
        Box(Modifier
            .size(50.dp, rectangleHeight)
            .background(Color.Blue))
    } else {
        Column {
            Box(Modifier
                .size(50.dp, rectangleHeight)
                .background(Color.Blue))
            Box(Modifier
                .size(50.dp, rectangleHeight)
                .background(Color.Gray))
        }
    }
}

Button(onClick = {
    height = if (height < 100) 100 else 80
}) {
    Text(text = "Click to switch height")}Copy the code

The effect

When the height is 80dp, only one blue color block is displayed:

When the height is 100dp, two color blocks are displayed:

Row

In Android, there is also the concept of Row TableRow, which is used on a table as a Row:

public class TableRow extends LinearLayout {
    / /...
}
Copy the code

Similar to Android’s TableRow, the Row effect in Compose is equivalent to a horizontal LinearLayout

Usage:

@Composable
inline fun Row(
    modifier: Modifier = Modifier,
    horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
    verticalAlignment: Alignment.Vertical = Alignment.Top,
    content: @Composable RowScope. () - >Unit
)
Copy the code

Parameter Meanings:

  • The modifier: modifier
  • HorizontalArrangement: Vertical range
  • VerticalAlignment: Horizontal alignment
  • Content: Indicates the content declaration

Borrow Google’s Demo

Row {
    // The child with no weight will have the specified size.
    Box(Modifier.size(40.dp, 80.dp).background(Color.Magenta))
    // Has weight, the child will occupy half of the remaining width.
    Box(Modifier.height(40.dp).weight(1f).background(Color.Yellow))
    // Has weight and does not fill, the child will occupy at most half of the remaining width.
    // Therefore it will occupy 80.dp (its preferred width) if the assigned width is larger.
    Box(
        Modifier.size(80.dp, 40.dp)
            .weight(1f, fill = false)
            .background(Color.Green)
    )
}
Copy the code

In a row, 40*80dp space is used first, and the remaining space (horizontally) is evenly divided by Weight. If you do not use fill, the given width will be used.

In the WorkShop, which provided more scenario demos, you can see that when using Weight, you always calculate the elements of a given size first and allocate the remaining space using Weight.

This is much more flexible and easy to use than the Android LinearLayout

Vertical alignment

VerticalAlignment allows you to specify verticalAlignment, such as vertical center alignment:

Row(verticalAlignment = Alignment.CenterVertically) {
    / /...
}
Copy the code

You can use:

  • Top Top aligned, default
  • CenterVertically aligned
  • Bottom aligned

Horizontal range

When the size of a Row is greater than the size of the content, you can adjust the position of the content:

For example, horizontally centered

 Row(
    modifier = Modifier.fillMaxWidth(),
    horizontalArrangement = Arrangement.Center) {
    // The child with no weight will have the specified size.
    Box(Modifier
        .size(40.dp, 80.dp)
        .background(Color.Magenta))
}
Copy the code

The effect

Column

Similar to Row, but arranged vertically

The reader is free to code to try out the effect without further elaboration

use

inline fun Column(
    modifier: Modifier = Modifier,
    verticalArrangement: Arrangement.Vertical = Arrangement.Top,
    horizontalAlignment: Alignment.Horizontal = Alignment.Start,
    content: @Composable ColumnScope. () - >Unit
) 
Copy the code

See how Row is used

conclusion

In Compose, we’ve learned the basic layout of Compose, but there are still some questions that should not be explored further: What happens if the content becomes too large for the container?

We will continue to explore this in subsequent chapters.