一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 3 天,点击查看活动详情。
先来看看官方文档中的两段话:
- 借助修饰符,您可以修饰或扩充可组合项。您可以使用修饰符来执行以下操作:
- 更改可组合项的尺寸、布局、行为和外观
- 添加信息,如无障碍标签
- 处理用户输入
- 添加高级互动,如使元素可点击、可滚动、可拖动或可缩放
- 修饰符函数的顺序 非常重要 。由于每个函数都会对上一个函数返回的
Modifier
进行更改,因此顺序会影响最终结果。
1. Modifier Api
尺寸 | 描述 | API |
---|---|---|
width | 组件的宽度 | width(width: Dp) width(intrinsicSize: IntrinsicSize) |
height | 组件的高度 | height(height: Dp) height(intrinsicSize: IntrinsicSize) |
size | 组件的宽高尺寸 | size(size: Dp) size(width: Dp, height: Dp) size(size: DpSize) |
wrapContentWidth | 自适应宽度 | wrapContentWidth(align: Alignment.Horizontal, unbounded: Boolean) |
wrapContentHeight | 自适应高度 | wrapContentHeight(align: Alignment.Vertical, unbounded: Boolean) |
wrapContentSize | 自适应宽高尺寸 | wrapContentSize(align: Alignment, unbounded: Boolean) |
fillMaxWidth | 宽度为最大值 | fillMaxWidth(fraction: Float) |
fillMaxHeight | 高度为最大值 | fillMaxHeight(fraction: Float) |
fillMaxSize | 宽高尺寸为最大值 | fillMaxSize(fraction: Float) |
布局 | 描述 | API |
---|---|---|
offset | 设置偏移量(依照布局方向) | offset(x: Dp, y: Dp) offset(offset: Density.() -> IntOffset) |
absoluteOffset | 设置偏移量(不考虑布局方向) | offset(x: Dp, y: Dp) offset(offset: Density.() -> IntOffset) |
padding | 设置内边距(依照布局方向) | padding(all: Dp) padding(horizontal: Dp, vertical: Dp) padding(start: Dp, top: Dp, end: Dp, bottom: Dp) padding(paddingValues: PaddingValues) |
absolutePadding | 设置内边距(不考虑布局方向) | absolutePadding(left: Dp, top: Dp, right: Dp, bottom: Dp) |
scale | 缩放 | scale(scale: Float) scale(scaleX: Float, scaleY: Float) |
rotate | 旋转角度 | rotate(degrees: Float) |
行为 | 描述 | API |
---|---|---|
clickable | 设置点击事件 | clickable(enabled: Boolean, onClickLabel: String?, role: Role?, onClick: () -> Unit |
combinedClickable | 设置单击事件、长点击事件、双击事件 | combinedClickable(enabled: Boolean, onClickLabel: String?, role: Role?, onLongClickLabel: String?, onLongClick: (() -> Unit)?, onDoubleClick: (() -> Unit)?, onClick: () -> Unit) |
verticalScroll | 支持纵向滚动 | verticalScroll(state: ScrollState, enabled: Boolean, flingBehavior: FlingBehavior?, reverseScrolling: Boolean) |
horizontalScroll | 支持横向滚动 | horizontalScroll(state: ScrollState, enabled: Boolean, flingBehavior: FlingBehavior?, reverseScrolling: Boolean) |
toggleable | 支持拨动 | toggleable(value: Boolean, enabled: Boolean, role: Role?, onValueChange: (Boolean) -> Unit) |
animateContentSize | 设置动画 | animateContentSize(animationSpec: FiniteAnimationSpec, finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)?) |
外观 | 描述 | API |
---|---|---|
backgroud | 设置背景 | background(color: Color, shape: Shape) |
border | 设置边框 | border(width: Dp, color: Color, shape: Shape = RectangleShape) border(width: Dp, brush: Brush, shape: Shape) |
alpha | 设置透明度 | alpha(alpha: Float) |
clip | 裁剪 | clip(shape: Shape) |
blur | 模糊 | blur(radius: Dp, edgeTreatment: BlurredEdgeTreatment) blur(radiusX: Dp, radiusY: Dp, edgeTreatment: BlurredEdgeTreatment) |
2. Modifier 函数的顺序对结果的影响
在这里提出一个内容区域的概念,所有的 【布局】Api 都会影响组件的内容区域,其他的Api则是作用于内容区域。下面来看一个例子:
可以看到:
左图的点击事件作用域区域,api顺序为:background -> padding -> background -> clickable
右图的点击事件作用域区域,api顺序为:clickable -> background -> padding -> background
解释:
- 最开始的时候,内容区域为一个 100dp x 100dp 的矩形区域
- 调用
background(Color.Red)
,将这块内容区域的背景设置为红色 - 调用
padding(20.dp)
,将内容区域由四周向内缩小20dp,剩下的内容区域为一个 60dp x 60dp 的矩形区域 - 调用
background(Color.Green)
,将剩下的内容区域的背景设置为绿色 - 调用
clickable{}
是设置单击事件,左图是在上述所有操作之前调用的,因此单击事件的作用范围是原始的 100dp x 100dp 的范围,右图是在上述所有操作之后调用的,因此单击事件的作用范围是最后剩下的 60dp x 60dp 的范围
再看例子2:
可以看到,我们首先是指定了一个内容区域为一个 100dp x 100dp 的蓝色矩形区域,
然后:
左图依次调用api:rotate -> background -> padding -> background
右图依次调用api:padding -> background -> rotate -> background
解释:
- 左图先调用
rotate(45f)
将内容区域沿顺时针旋转45°,然后将内容区域涂成红色,接着调用padding(20.dp)
将内容区域由四周向内缩小20dp,最后将内容区域涂成绿色。 - 右图先调用
padding(20.dp)
将内容区域由四周向内缩小20dp,然后将内容区域涂成红色,接着调用rotate(45f)
将内容区域沿顺时针旋转45°,最后将内容区域涂成绿色。 - 两者的点击均完全作用在最后的绿色区域上。
可以看到,我们调用 rotate(45.dp)
之后,新的内容区域的四个角其实已经超出了之前的内容区域,而且每一次调用api,都是在前一个内容区域的基础上进行叠加处理。
3.总结
- Modifier的属性,大致上可以分成四大类:尺寸、区域、行为、外观,且属性api调用的顺序 非常重要 。
- 每次调用api,都是在前面的基础上进行叠加操作,且并不会影响之前的效果,但后面的api效果会受到前面的api影响。
- 设置内边距、旋转等影响内容区域摆放位置的api,会将内容区域整体带着走,并不会仅仅局限于之前的内容区域范围内。