Compose 修饰符
修饰符允许您修饰或扩充可组合项。通过修饰符,您可以:
- 更改可组合项的大小、布局、行为和外观
- 添加信息,如无障碍标签
- 处理用户输入
- 添加高级互动,如使元素可点击、可滚动、可拖动或可缩放
基本使用
修饰符是标准的 Kotlin 对象,通过调用 Modifier 类函数创建:
@Composable
private fun Greeting(name: String) {
Column(modifier = Modifier.padding(24.dp)) {
Text(text = "Hello,")
Text(text = name)
}
}
可以将多个修饰符函数链式连接:
@Composable
private fun Greeting(name: String) {
Column(
modifier = Modifier
.padding(24.dp)
.fillMaxWidth()
) {
Text(text = "Hello,")
Text(text = name)
}
}
最佳实践是让所有可组合项接受 modifier 参数,并将其传递给第一个子项,以提高代码可重用性。
修饰符顺序很重要
修饰符函数的顺序非常重要,因为每个函数都会对上一个函数返回的 Modifier 进行更改:
@Composable
fun ArtistCard(/*...*/) {
val padding = 16.dp
Column(
Modifier
.clickable(onClick = onClick)
.padding(padding)
.fillMaxWidth()
) {
// 整个区域(包括内边距)都是可点击的
}
}
如果顺序相反,内边距区域将不会响应点击:
@Composable
fun ArtistCard(/*...*/) {
val padding = 16.dp
Column(
Modifier
.padding(padding)
.clickable(onClick = onClick)
.fillMaxWidth()
) {
// 仅内容区域可点击,内边距不可点击
}
}
常见内置修饰符
padding 和 size
默认情况下,Compose 布局会封装其子项,但您可以使用 size 修饰符设置尺寸:
@Composable
fun ArtistCard(/*...*/) {
Row(
modifier = Modifier.size(width = 400.dp, height = 100.dp)
) {
Image(/*...*/)
Column { /*...*/ }
}
}
如果指定尺寸不符合父项约束,可以使用 requiredSize 修饰符强制设置:
@Composable
fun ArtistCard(/*...*/) {
Row(
modifier = Modifier.size(width = 400.dp, height = 100.dp)
) {
Image(
/*...*/
modifier = Modifier.requiredSize(150.dp)
)
Column { /*...*/ }
}
}
使用 fillMaxHeight 使子项填充父项的所有可用高度:
@Composable
fun ArtistCard(/*...*/) {
Row(
modifier = Modifier.size(width = 400.dp, height = 100.dp)
) {
Image(
/*...*/
modifier = Modifier.fillMaxHeight()
)
Column { /*...*/ }
}
}
在文本基线上方添加内边距:
@Composable
fun ArtistCard(artist: Artist) {
Row(/*...*/) {
Column {
Text(
text = artist.name,
modifier = Modifier.paddingFromBaseline(top = 50.dp)
)
Text(artist.lastSeenOnline)
}
}
}
偏移
使用 offset 修饰符相对于原始位置放置布局:
@Composable
fun ArtistCard(artist: Artist) {
Row(/*...*/) {
Column {
Text(artist.name)
Text(
text = artist.lastSeenOnline,
modifier = Modifier.offset(x = 4.dp)
)
}
}
}
Compose 中的作用域安全
某些修饰符只能应用于特定可组合项的子项。Compose 通过自定义作用域强制实施此安全机制。
matchParentSize(在 Box 中)
使子项与父项 Box 尺寸相同,而不影响 Box 尺寸:
@Composable
fun MatchParentSizeComposable() {
Box {
Spacer(
Modifier
.matchParentSize()
.background(Color.LightGray)
)
ArtistCard()
}
}
Row 和 Column 中的 weight
使用 weight 修饰符使可组合项在父容器内按比例分配空间:
@Composable
fun ArtistCard(/*...*/) {
Row(
modifier = Modifier.fillMaxWidth()
) {
Image(
/*...*/
modifier = Modifier.weight(2f)
)
Column(
modifier = Modifier.weight(1f)
) {
/*...*/
}
}
}
提取和重复使用修饰符
将修饰符链提取到变量中,以便在多个可组合项中重复使用:
val reusableModifier = Modifier
.fillMaxWidth()
.background(Color.Red)
.padding(12.dp)
在观察频繁变化的状态时提取修饰符
在动画等频繁重组的场景中,提取修饰符可避免不必要的分配:
// 不好的做法:每次重组都会重新分配修饰符
@Composable
fun LoadingWheelAnimation() {
val animatedState = animateFloatAsState(/*...*/)
LoadingWheel(
// 每帧动画都会重新创建此修饰符!
modifier = Modifier
.padding(12.dp)
.background(Color.Gray),
animatedState = animatedState
)
}
// 好的做法:提取修饰符
val reusableModifier = Modifier
.padding(12.dp)
.background(Color.Gray)
@Composable
fun LoadingWheelAnimation() {
val animatedState = animateFloatAsState(/*...*/)
LoadingWheel(
// 重复使用同一实例,无额外分配
modifier = reusableModifier,
animatedState = animatedState
)
}
重复使用未限定作用域的修饰符
val reusableModifier = Modifier
.fillMaxWidth()
.background(Color.Red)
.padding(12.dp)
@Composable
fun AuthorField() {
HeaderText(
// ...
modifier = reusableModifier
)
SubtitleText(
// ...
modifier = reusableModifier
)
}
重复使用限定作用域的修饰符
Column(/*...*/) {
val reusableItemModifier = Modifier
.padding(bottom = 12.dp)
// align 修饰符需要 ColumnScope
.align(Alignment.CenterHorizontally)
.weight(1f)
Text1(
modifier = reusableItemModifier,
// ...
)
Text2(
modifier = reusableItemModifier
// ...
)
// ...
}
进一步链接提取的修饰符
使用 .then() 函数将提取的修饰符与其他修饰符链接:
val reusableModifier = Modifier
.fillMaxWidth()
.background(Color.Red)
.padding(12.dp)
// 追加到可重用修饰符
reusableModifier.clickable { /*...*/ }
// 将可重用修饰符追加到其他修饰符
otherModifier.then(reusableModifier)
注意:修饰符的顺序很重要,会影响最终效果。