《Jetpack Compose系列学习》-12 修饰符——Modifier

1,294 阅读3分钟
Modifier

大家对修饰符Modifier应该很熟悉了,前面Column、Row、Box和Text等都用到了这个修饰符,它是一个有序的、不可变的修饰元素集合,用于给Compose UI元素添加装饰、行为,如background、padding、点击事件等,或者给Text设置单行、给Button设置各种点击状态等行为。

Modifier非常强大,你能想到的操作它基本都可以实现,包括滚动、拖动、缩放等,它的东西比较多,我们从几种常用的修饰符功能。

内边距padding

Modifier可以修改内边距,就是padding,如:

Text("程序员", modifier = Modifier.padding(20.dp))

可以看到Modifier来添加内边距,只需要调用padding方法传入对应的边距值即可。先看看padding的源码是怎么定义的:

@Stable
fun Modifier.padding(
    start: Dp = 0.dp,
    top: Dp = 0.dp,
    end: Dp = 0.dp,
    bottom: Dp = 0.dp
)

@Stable
fun Modifier.padding(
    horizontal: Dp = 0.dp,
    vertical: Dp = 0.dp
)

@Stable
fun Modifier.padding(all: Dp)

我们可以看到padding有多种设置方式,可以单独设置一边,也可以设置横向纵向,还可以统一设置所有的。上面的实例代码默认设置上下左右所有的内边距: image.png

设置控件的尺寸

我们之前的实例代码中是怎么设置尺寸的?Android View中直接可以在xml布局里写死宽高,也可以自适应或者充满父布局:

<TextView
    android:layout_width="100dp"
    android:layout_height="40dp"
    android:gravity="center"
    android:text="Text1"/>
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:text="Text2"/>
<TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:text="Text3"/>

那么Compose中,前面的示例中也有用到,如充满父布局:

Text("程序员", modifier = Modifier.fillMaxSize())

或者也可以只充满宽或者高:

Text("程序员", modifier = Modifier.fillMaxWidth()) // 充满宽
Text("程序员", modifier = Modifier.fillMaxHeight()) // 充满高

当你什么都不做的时候,就是默认的自适应大小,如Android View中的Wrap_content。如果我们想设置固定值大小的话可以这样:

Text("程序员", modifier = Modifier.size(100.dp)) // 宽高都是100dp
Text("程序员", modifier = Modifier.size(width = 100.dp, height = 80.dp)) // 宽100dp 高80dp

如果希望子布局的尺寸设置为父控件Box相同,但是不影响Box的尺寸大小,我们可以使用matchParentSize修饰符。matchParentSize仅在Box作用域内可用,意味着它仅适用于Box可组合项的直接子项。我们看个例子,内部Spacer从其父控件Box获取自己的尺寸,而后者又从其包含的Text获取自己的尺寸:

Box {
    Spacer(modifier = Modifier.matchParentSize().background(Color.Red))
    Text("程序员", fontSize = 30.sp)
}

image.png

Row和Column中的Weight修饰符

在Android View中线性布局也经常用weight,在Compose中我们是这么用weight的:

Row(
    Modifier
        .fillMaxSize()
        .padding(10.dp)) {
    Box(modifier = Modifier.weight(2f).height(50.dp).background(Color.Blue))
    Box(modifier = Modifier.weight(1f).height(50.dp).background(Color.Red))
}

image.png

可以看出,宽度蓝色:红色是2:1,正好是我们设置的对应weight的比例大小。

控件添加点击事件

Android中我们通过控件view.setOnClickListener来设置点击事件,Compose中Modifier可以设置点击事件:

Row(
    Modifier
        .fillMaxSize()
        .padding(10.dp)) {
    Box(modifier = Modifier.weight(2f).height(50.dp).background(Color.Blue))
    Box(modifier = Modifier.weight(1f).height(50.dp).background(Color.Red).clickable {
        Log.e("LM" , "点击了Box")
    })
}

// 点击红色Box后可以在控制台看到日志:
// 2022-04-04 15:08:52.793 19862-19862/com.carey.compose E/LM: 点击了Box
控件添加圆角

Android View中实现圆角我们都是定义shape.xml,或者通过自定义控件通过canvas等去实现。但是在Compose中还是很容易的。用Modifier.shadow:

@Suppress("UnnecessaryComposedModifier")
@Stable
fun Modifier.shadow(
    elevation: Dp, // 阴影的高度
    shape: Shape = RectangleShape, // shape
    clip: Boolean = elevation > 0.dp // 是否裁剪其内容
) // 省略...

我们看到它只有三个参数,第一个参数是设置阴影的高度,类型为Dp,直接设置即可;第二个参数是shape,想设置圆角的话,通过它即可实现;第三个参数是clip,是否裁剪其内容,默认根据阴影高度来判断,如:

Box(contentAlignment = Alignment.Center) {
        Image(painter = painterResource(id = R.drawable.small),
//            modifier = Modifier.size(150.dp).shadow(elevation = 10.dp, shape = MaterialTheme.shapes.medium),
            modifier = Modifier.size(150.dp).shadow(elevation = 10.dp, shape = RoundedCornerShape(18.dp)), // 指定圆角大小值
            contentDescription = ""
        )
    }

image.png

如果不想要阴影,可以把elevation值设置成0,然后手动打开裁剪clip属性即可:

Box(contentAlignment = Alignment.Center) {
        Image(painter = painterResource(id = R.drawable.small),
//            modifier = Modifier.size(150.dp).shadow(elevation = 10.dp, shape = MaterialTheme.shapes.medium),
            modifier = Modifier.size(150.dp).shadow(elevation = 0.dp, shape = RoundedCornerShape(18.dp), clip = true),
            contentDescription = ""
        )
    }

image.png

Modifier.shadow不只可以给Image设置圆角,其它可组合项也可以设置圆角。后期我们会介绍复杂的控件等。