“This is the 15th day of my participation in the First Challenge 2022. For details: First Challenge 2022.”

Jetpack Compose Series (4) – Modifiers

The modifier

Modifier, the Modifier in JetpackCompose, can be used to modify the following:

· Change the size, layout, behavior, and appearance of composable items

· Add information such as accessibility labels

· Process user input

· Add advanced interactions, such as making elements clickable, scrollable, draggable or zoomable

Modifiers are standard Kotlin objects that can be created by calling one of the Modifier class functions, for example:

@Preview(showBackground = true) @Composable fun DefaultPreview() { Column(modifier = Modifier.padding(35.dp)){ Text(text  = "Hello") Text(text = "Modifier") } }Copy the code

The resulting two Text lists with a padding value of 15dp look like this:

You can use the Modifier to adjust the layout effect by setting extension functions such as the padding in the View XML file, as well as the width and height properties.

Background and Transparency alpha

· Background (color: color, shape: shape?) Shape specifies a shape. For example, you can use a RoundedCornerShape to specify the size of a rounded corner.

· Alpha (alpha: Float) : Set transparency, ranging from 0 to 1.

For a gradient background, you can use background(Brush: Brush, Shape: Shape? , alpha: Float?) . The Brush parameter is the gradient we specify, such as the verticalGradient created using verticalGradient:

@Composable fun CustomView() { Column(modifier = Modifier.background( Brush.Verticalgradient (listOf(color.blue, color.red)).alpha(0.3f)){Modifier (Text = "Hello") Text(Text = "Modifier")}}Copy the code

The corresponding generated effect is:

Note that the alpha transparency set here refers to the transparency of the object in {}. If you want to change the background transparency, you need to set alpha inside background(), for example:

When setting up Brush, you’ll find that you can set a number of functions:

These functions can do landscape gradients, linear gradients, scan gradients, specify start and end positions, etc., which I won’t cover here.

The size of the ( size ) High and wide

· Width (width: dp): set the width in dp.

· Height (height: DP): Set the height in dp.

· Size (width: dp,height: dp) : set the width and height in unit dp.

The following two pieces of code are equivalent:

Column(modifier = Modifier
    .background(Color.Red)
    .width(60.dp)
    .height(120.dp)){
    Text(text = "Hello")
    Text(text = "Modifier")
}
Column(modifier = Modifier
    .background(Color.Red)
    .size(60.dp,120.dp)){
    Text(text = "Hello")
    Text(text = "Modifier")
}
Copy the code

The implementation effect is also consistent:

A border (border) And click the

· Border (width: Dp, color: color, shape: shape?) : Adds a border. The color parameter specifies the color, and the shape parameter specifies the thickness and shape.

· Clickable () : Makes any control clickable with a water ripple effect.

@Composable
fun CustomView() {
    Column(modifier = Modifier
        .background(Color.Red)
        .width(60.dp)
        .height(120.dp)
        .clickable (onClick = {
            Log.i("clickEvent"," get clicked ! ")
        })){
        Text(text = "Hello")
        Text(text = "Modifier")
    }
}
Copy the code

Click the list, and the corresponding console output log is:

Of course, clickable() also has other parameters that can be set to unclickable:

Clickable (Enabled: Boolean = true, // Whether to click onClickLabel: String? = null, // semantic/accessibility tag role: role? = null, // Click the type of the element, such as Button, Checkbox, Image, etc. For accessibility services. OnClick: () -> UnitCopy the code

· combinedClickable: can set long press, multiple clicks, common click monitor, etc. Note: this is experimental API may be deleted at any time (using the requirements method and the method is invoked when they take @ ExperimentalFoundationApi). The following is an example:

@ExperimentalFoundationApi
@Composable
fun CustomView() {
    Column(modifier = Modifier
        .background(Color.Red)
        .width(60.dp)
        .height(120.dp)
        .combinedClickable (
            onLongClick = {
                Log.i("clickEvent"," onLongClick event happened ! ")
            },
            onDoubleClick = {
                Log.i("clickEvent"," onDoubleClick event happened ! ")
            },
            onClick = {
                Log.i("clickEvent"," onClick event happened ! ")
            }
                )){
        Text(text = "Hello")
        Text(text = "Modifier")
    }
}
Copy the code

Corresponding logs can also be correctly output on the console:

· onFocusChanged() : Listens for focus change events.

· focusable() : Sets the focus.

· requiredWidth(width: Dp) : It is mandatory to set the width and can ignore the parent element’s width and height limit.

· requiredHeight(height: Dp) : It is mandatory to set the height. You can ignore the width and height limit of the parent element.

· heightIn(min: Dp, Max: Dp), maximum and minimum heights are specified. WidthIn similarly.

· Padding (all: Dp): Leave space around the elements, i.e. inside margin.

Rotate (degrees: Float) : Sets the rotation degree.

· Scale (scaleX: Float, scaleY: Float) : Set the scale, if negative can achieve mirror effect.

· horizontalScroll(), which allows child elements to scroll horizontally when width is greater than the maximum limit. (We can scroll horizontally beyond the width of the screen)

· verticalScroll() allows child elements to scroll vertically when width is greater than the maximum limit.

Such as:

Row(Modifier.horizontalScroll(rememberScrollState())) {
    Box(
        Modifier
            .size(700.dp, 50.dp)
            .background(Color.Red)
    ){
        Text("123")
    }
}
Copy the code

The corresponding output effect is:

The red item can be dragged left and right.

· fillMaxHeight(fraction: Float = 1f) : The child layout fills in all the available heights allowed by the parent item, similar to match_parent in XML. The default value is 1f. Same with fillMaxSize and fillMaxWidth.

For example:

RequiredSize (100.dp).background(color.red)) {Box(Modifier.fillMaxWidth(0.6f).fillMaxHeight(0.5f)) .background(color = Color.Yellow) ) }Copy the code

The corresponding effect is:

· wrapContentSize: Sets the components to be arranged if their width and height are smaller than the defined minimum width and height (see if the name reminds of wrAP_content).

· sizeIn(minWidth: Dp,minHeight: Dp,maxWidth: Dp,maxHeight: Dp) : set the minimum and maximum width and height, width between minWidth and maxWidth, height between minHeight and maxHeight.

Column { Box( Modifier .sizeIn(minWidth = 50.dp, minHeight = 50.dp) .size(20.dp) .background(Color.Black) ) Box( Modifier .sizeIn(minWidth = 50.dp, MinHeight = 50.dp).wrapContentSize(align.topCenter).size(20.dp)// Set the Alignment size to less than the minHeight and the final render is 20*20. Align topcenter.background (color.red))}Copy the code

The corresponding effect is:

From the code, we can see that the size of the black Box is less than the minimum width and height, and the final rendering is 50It’s 50 by 50. The red Box sets the wrapContentSize, which is less than the minimum width and height, to render 20The length and width of 20 are aligned with TopCenter.

Of course, you can also set the width and height separately:

/ / set the width wrapContentWidth (align: Alignment. Horizontal = Alignment. CenterHorizontally, unbounded: Boolean = false) / / set the height wrapContentHeight (align: Alignment. Vertical = Alignment. CenterVertically, unbounded: Boolean = false )Copy the code

We modify two properties in the code above:

Column { Box( Modifier .sizeIn(minWidth = 50.dp, MinHeight = 50. Dp). WrapContentHeight (Alignment. CenterVertically), height (20. Dp) / / 20 dp, wide and 50 dp, Background (color.black)) Box(Modifier. SizeIn (minWidth = 50.dp, MinHeight = 50. Dp). WrapContentWidth (Alignment. CenterHorizontally), width (20. Dp) / / 20 dp wide, high 50 dp, Background (color.red))}Copy the code

The corresponding effect is shown as follows:

Decorator order

The order of the Modifier functions is important; each function changes the Modifier returned by the previous function.

Such as:

Column {
    Box(
        Modifier
            .size(100.dp)
            .background(Color.Red)
            .padding(25.dp)
    )
    Box(
        Modifier
            .size(100.dp)
            .padding(25.dp)
            .background(Color.Yellow)
    )
}
Copy the code

The corresponding effect is:

If you look at the code, it’s not hard to see that if you set the background first and then set the padding value, then the padding value is based on the background. If the padding value is set first, then the background is set for the layout after the padding. The reason is simple, simply becauseEach function changes the Modifier returned by the previous function. Of course, click events are also affected, but only in the click area, which is not hard to understand and I won’t go into details here.