3、Jetpack Compose 入门 --- Modifier的使用

568 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第 3 天,点击查看活动详情

先来看看官方文档中的两段话:

  1. 借助修饰符,您可以修饰或扩充可组合项。您可以使用修饰符来执行以下操作:
    • 更改可组合项的尺寸、布局、行为和外观
    • 添加信息,如无障碍标签
    • 处理用户输入
    • 添加高级互动,如使元素可点击、可滚动、可拖动或可缩放
  2. 修饰符函数的顺序 非常重要 。由于每个函数都会对上一个函数返回的 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则是作用于内容区域。下面来看一个例子: GIF 2022-2-17 0-36-06.gif 可以看到:
左图的点击事件作用域绿色\color{#00FF00}{绿色}区域,api顺序为:background -> padding -> background -> clickable
右图的点击事件作用域红色\color{red}{红色}区域,api顺序为:clickable -> background -> padding -> background

解释:

  1. 最开始的时候,内容区域为一个 100dp x 100dp 的矩形区域
  2. 调用 background(Color.Red),将这块内容区域的背景设置为红色
  3. 调用 padding(20.dp),将内容区域由四周向内缩小20dp,剩下的内容区域为一个 60dp x 60dp 的矩形区域
  4. 调用 background(Color.Green),将剩下的内容区域的背景设置为绿色
  5. 调用 clickable{} 是设置单击事件,左图是在上述所有操作之前调用的,因此单击事件的作用范围是原始的 100dp x 100dp 的范围,右图是在上述所有操作之后调用的,因此单击事件的作用范围是最后剩下的 60dp x 60dp 的范围

再看例子2: GIF 2022-2-19 0-29-37.gif

可以看到,我们首先是指定了一个内容区域为一个 100dp x 100dp 的蓝色矩形区域,
然后:
左图依次调用api:rotate -> background -> padding -> background
右图依次调用api:padding -> background -> rotate -> background

解释:

  1. 左图先调用 rotate(45f) 将内容区域沿顺时针旋转45°,然后将内容区域涂成红色,接着调用 padding(20.dp) 将内容区域由四周向内缩小20dp,最后将内容区域涂成绿色。
  2. 右图先调用 padding(20.dp) 将内容区域由四周向内缩小20dp,然后将内容区域涂成红色,接着调用 rotate(45f) 将内容区域沿顺时针旋转45°,最后将内容区域涂成绿色。
  3. 两者的点击均完全作用在最后的绿色区域上。

可以看到,我们调用 rotate(45.dp) 之后,新的内容区域的四个角其实已经超出了之前的内容区域,而且每一次调用api,都是在前一个内容区域的基础上进行叠加处理。

3.总结

  1. Modifier的属性,大致上可以分成四大类:尺寸、区域、行为、外观,且属性api调用的顺序 非常重要
  2. 每次调用api,都是在前面的基础上进行叠加操作,且并不会影响之前的效果,但后面的api效果会受到前面的api影响。
  3. 设置内边距、旋转等影响内容区域摆放位置的api,会将内容区域整体带着走,并不会仅仅局限于之前的内容区域范围内。