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 specified
Compose
Both 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.