Modifier修饰符
Compose提供了Column、Row、Box 三种布局组件,其中Column/Row 对应 View体系中LinearLayout的 Vertical/Horizontal 方向,Box相当于 FrameLayout,而借助Modifier修饰符,可以修饰或扩充布局组件。通常使用修饰符来执行以下操作:
- 更改可组合项的大小、布局、行为和外观
- 添加信息,如无障碍标签
- 处理用户输入
- 添加高级互动,如使元素可点击、可滚动、可拖动或可缩放
Modifier 以链式调用的方式来设置组件的样式,每个UI 组件都会有一个modifier参数,通过传入该参数来改变组件。
常用修饰符
列举一些常用的Modifier 修饰符:
- Modifier.width(width: Dp)
- Modifier.height(height: Dp)
- Modifier.size(width: Dp, height: Dp)
设置具体的宽高,单位是dp, 如设置宽度500dp,高度100dp:
kotlin
.width(500.dp).height(100.dp)
//或者直接在size里设置宽高
//.size(width = 500.dp, height = 100.dp)
如果子布局中有 requiredSize
,那么requiredSize的优先级更高一些,如果希望尺寸固定不变,而不考虑传入的约束条件,请使用 requiredSize 修饰符。
- Modifier.fillMaxWidth(fraction: Float = 1f) :子布局填充父项允许的所有可用宽度
- Modifier.fillMaxHeight(fraction: Float = 1f) :子布局填充父项允许的所有可用高度
- Modifier.fillMaxSize(fraction: Float = 1f) :子布局填充父项允许的所有可用宽高
让内容填充(可能仅部分填充)传入的测量约束的最大宽高,其中fraction 取值范围是[0.0, 1.0],默认是1.0。
- Modifier.background(color: Color, shape: Shape = RectangleShape)
设置背景,如果想设置渐变色的背景,可以通过Brush的方式添加,如下:
kotlin
Modifier.background(brush: Brush,
shape: Shape = RectangleShape,
/*@FloatRange(from = 0.0, to = 1.0)*/
alpha: Float = 1.0f
)
使用:
kotlin
val bgGradient = Brush.verticalGradient(
colors = listOf(Color.Red, Color.Green, Color.Yellow, Color.Cyan))
//设置渐变色
Row(modifier = Modifier.background(bgGradient)){
...
}
- Modifier.border(border: BorderStroke, shape: Shape)
- Modifier.border(width: Dp, color: Color, shape: Shape)
- Modifier.border(width: Dp, brush: Brush, shape: Shape)
修改元素,指定外观的边框 ,边框可以指定颜色、粗细、Shape形状等,并进行裁剪。
- Modifier.padding(all: Dp)
- Modifier.padding(horizontal: Dp, vertical: Dp)
- Modifier.padding(start: Dp, top: Dp, end: Dp, bottom: Dp)
设置内外边距,传统的View 体系中有padding和margin的区分,而在Compose中只有一个padding修饰符,根据不同的位置可以表示内、外边距。可以简单理解为:padding在元素的"外部"应用外边距,而在元素的"内部"应用内边距。
- Modifier.offset(x: Dp = 0.dp, y: Dp = 0.dp)
offset 用来偏移内容,可以直接传入x y,单位是dp,也可以使用offset的重载方法,返回一个IntOffset,两种写法是等价的:
kotlin
//1
Modifier.offset(x = 100.dp, y = 100.dp)
//2
Modifier.offset {IntOffset(100.dp.roundToPx(), 100.dp.roundToPx())}
offset 可以是正数,也可以是负数。offset 修饰符根据布局方向水平应用。从左到右布局时,右移为正;反之从右到左布局时,左移为正。如果不考虑布局方向,可以使用 absoluteOffset 修饰符,不管如何布局,会强制向右布局。
kotlin
//3 absoluteOffset强制从左向右移动
Modifier.absoluteOffset(x = 100.dp, y = 100.dp)
//4
Modifier.absoluteOffset {IntOffset(100.dp.roundToPx(), 100.dp.roundToPx())}
- Modifier.align(alignment: Alignment) :在Box的子控件中使用,表示将内容拉取到Box中的特定Alignment位置。
Alignment 的取值有:TopStart、TopCenter、TopEnd、CenterStart、Center、CenterEnd、BottomStart、BottomCenter、BottomEnd
。 - Modifier.align(alignment: Alignment.Vertical) :在Row的子控件中使用,表示在Row 中垂直对齐元素。
Alignment.Vertical 的取值有:Top、CenterVertically、Bottom
。 - Modifier.align(alignment: Alignment.Horizontal) :在Column 的子控件中使用,表示在Column 中水平对齐元素。
Alignment.Horizontal 的取值有:Start、CenterHorizontally、End
。
更多Modifier修饰符的用法参见:Modifier修饰符列表:https://developer.android.com/jetpack/compose/modifiers-list?hl=zh-cn
作用域限定
某些Modifier修饰符只能应用于某些可组合项的子项,Compose 通过自定义作用域强制实施此安全机制。
matchParentSize(作用于Box中)
在Box中,如果希望某个子项与父项 Box 同样大,而不影响 Box 尺寸,可以使用 matchParentSize 修饰符。
matchParentSize 仅适用于Box的子控件中,可以保证当前组件的尺寸与父组件相同,父组件如果未设置宽高默认是wrapContent;而如果改为使用fillMaxSize,则会被设置为父组件所允许的最大尺寸。示例如下:
kotlin
@Composable
private fun BoxSample() {
Box {
Spacer(modifier = Modifier.matchParentSize().background(Color.Yellow))
Text(text = "Jetpack Compose", modifier = Modifier.padding(10.dp))
}
}
执行结果:
上述代码中,如果将matchParentSize
改为fillMaxSize
,则执行结果为:
weight(作用于Column 和 Row 中)
weight只能在Column 和 Row 中使用,跟View体系中LinearLayout中的weight是一个概念。示例如下:
kotlin
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
//设置渐变色
val bgGradient = Brush.verticalGradient(
colors = listOf(Color.Red, Color.Green, Color.Yellow, Color.Cyan)
)
Row(
modifier = Modifier
.background(bgGradient)
.fillMaxWidth()
.height(40.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = "Tab1",
modifier = Modifier.weight(1f), //1
textAlign = TextAlign.Center,
)
Image(
modifier = Modifier
.wrapContentSize(align = Alignment.BottomCenter, true)
.weight(1f) //2
.clip(CircleShape)
.border(width = 2.dp, Color.Red, CircleShape)
.requiredSize(80.dp),
painter = painterResource(id = R.drawable.icon_cat_w),
contentScale = ContentScale.Crop,
contentDescription = ""
)
Text(
text = "Tab2",
modifier = Modifier.weight(1f), //3
textAlign = TextAlign.Center,
)
}
}
Row中的子控件通过在1、2、3处设置weight 来均分横向宽度,执行结果:
上述示例中是一个综合示例,不仅使用了weight修饰符,还是用的clip、border等,最终展示是三个均分的底部Tab控件,其中图片大小不受父控件的约束(通过requiredSize实现的)。
注意修饰符顺序
修饰符函数的顺序非常重要。因为每个Modifier 修饰符函数都会对上一个函数返回的 Modifier 进行更改,因此顺序会影响最终结果。如:
kotlin
Box(
modifier = Modifier
.size(200.dp, 100.dp)
.background(Color.Gray)
.padding(20.dp)
.border(1.dp, Color.Red, RectangleShape)
.padding(20.dp)
.background(Color.Green)
)
对于border而言,在其前面的设置padding 可以认为是外边距,在其后面设置的 padding可以认为是内边距。通过修饰符的前后顺序可以控制内外边距,这也说明了为什么没有外边距修饰符,而只有 padding 修饰符。