Android Compose UI - Modifier 链条 + Column/Row/Box 布局

2.1 Modifier 的本质

Modifier 是一个有序的装饰器链表,每个元素都是一个 Modifier.Element,它们依次对 Composable 进行变换。

Text(
    text = "Hello",
    modifier = Modifier
        .fillMaxWidth()           // 1. 宽度撑满父布局
        .padding(16.dp)           // 2. 四周添加 16dp 内边距
        .background(Color.Yellow) // 3. 背景色黄色
        .clickable { }            // 4. 可点击
)

执行顺序:从外到内(从左到右)依次应用。上面例子中,先 fillMaxWidth,然后在撑满的基础上加 padding,再在 padding 后的区域涂背景,最后让这个区域可点击。

2.2 高频 Modifier 分类速查

尺寸与布局

Modifier 说明 示例
.size(width, height) 固定宽高 Modifier.size(48.dp)
.width(w) / .height(h) 单独设置宽或高 Modifier.width(100.dp)
.fillMaxWidth(fraction) 撑满父宽度(可指定比例) Modifier.fillMaxWidth(0.5f) 占一半
.fillMaxHeight() 撑满父高度
.fillMaxSize() 撑满父宽高
.requiredSize(...) 强制尺寸(忽略父约束) 慎用
.defaultMinSize(minW, minH) 设置最小尺寸

外边距与内边距

Modifier 说明
.padding(all) 四个方向统一内边距
.padding(start, top, end, bottom) 分别设置
.padding(horizontal, vertical) 水平/垂直
.offset(x, y) 偏移(不影响布局占位)
.wrapContentSize(align) 让子元素按自身大小放置,可指定对齐

背景与边框

Modifier 说明
.background(color, shape) 背景色 + 形状
.border(width, color, shape) 边框
.clip(shape) 裁切(不会自动添加背景)
.shadow(elevation, shape) 阴影(Material 组件自带)

交互与手势

Modifier 说明
.clickable(enabled, onClickLabel, onClick) 点击事件
.combinedClickable(onClick, onDoubleClick, onLongClick) 组合点击
.selectable(selected, onClick) 单选/多选
.toggleable(value, onValueChange) 开关状态
.draggable(...) / .swipeable(...) 拖拽/滑动
.pointerInput(block) 自定义手势

滚动与嵌套

Modifier 说明
.verticalScroll(state) 垂直滚动
.horizontalScroll(state) 水平滚动
.nestedScroll(connection) 嵌套滚动连接

其他

Modifier 说明
.alpha(float) 透明度
.rotate(degrees) 旋转
.scale(scaleX, scaleY) 缩放
.zIndex(z) Z 轴顺序
.testTag(tag) 测试标签
.graphicsLayer { } 高效视觉变换(不触发重测)

2.3 Modifier 顺序的经典陷阱

// 错误顺序:先 background 再 padding
Modifier
    .background(Color.Red)   // 红色背景铺满整个可用区域
    .padding(16.dp)          // 然后把内容往里挤 16dp,留下红色边框?
                             // 实际上背景已经画完了,padding 只是移动内容,背景不变
// 正确顺序:先 padding 再 background
Modifier
    .padding(16.dp)          // 预留 16dp 空白
    .background(Color.Red)   // 红色背景只画在 padding 后的区域内

经验法则:按照"从外到内"的顺序思考。

  1. 尺寸约束(fillMaxWidth, size
  2. 外边距/内边距(padding, offset
  3. 装饰(background, border, clip, shadow
  4. 交互(clickable, pointerInput
  5. 滚动/手势(scrollable, draggable

2.4 三大布局:Column、Row、Box

Column —— 垂直线性布局

Column(
    modifier = Modifier.fillMaxSize().padding(16.dp),
    horizontalAlignment = Alignment.CenterHorizontally,  // 子项水平对齐
    verticalArrangement = Arrangement.spacedBy(8.dp)      // 子项垂直间距
) {
    Text("Item 1")
    Text("Item 2")
    Text("Item 3")
}

verticalArrangement 选项

效果
Arrangement.Top 顶部对齐(默认)
Arrangement.Center 垂直居中
Arrangement.Bottom 底部对齐
Arrangement.SpaceEvenly 均匀分布,两端也有间距
Arrangement.SpaceBetween 两端贴边,中间均匀分布
Arrangement.SpaceAround 两端半间距,中间均匀
Arrangement.spacedBy(dp) 最常用:固定间距

horizontalAlignment 选项StartCenterHorizontallyEnd

Row —— 水平线性布局

参数与 Column 对称:

  • horizontalArrangement:控制水平方向排列(对应 Column 的 verticalArrangement)
  • verticalAlignment:控制垂直方向对齐(对应 Column 的 horizontalAlignment)
Row(
    modifier = Modifier.fillMaxWidth(),
    verticalAlignment = Alignment.CenterVertically,
    horizontalArrangement = Arrangement.SpaceBetween
) {
    Text("Left")
    Text("Right")
}

Box —— 层叠布局(类似 FrameLayout)

子项默认从左上角开始堆叠,可以通过 contentAlignment 设置默认对齐,或通过 Modifier.align() 单独控制每个子项的对齐。

Box(
    modifier = Modifier.size(200.dp).background(Color.LightGray),
    contentAlignment = Alignment.Center   // 所有子项默认居中
) {
    // 底层
    Box(Modifier.size(150.dp).background(Color.Red))
    // 上层文字
    Text("Hello", color = Color.White)
    // 右上角的关闭按钮
    Icon(
        Icons.Default.Close,
        contentDescription = "Close",
        modifier = Modifier.align(Alignment.TopEnd).padding(8.dp)
    )
}

常用对齐值TopStartTopCenterTopEndCenterStartCenterCenterEndBottomStartBottomCenterBottomEnd

2.5 weight 权重 —— 在 Row/Column 中按比例分配空间

Row(Modifier.fillMaxWidth()) {
    Text("A", Modifier.weight(1f).background(Color.Red))
    Text("B", Modifier.weight(2f).background(Color.Green))
    Text("C", Modifier.weight(1f).background(Color.Blue))
}
// A 占 1/4,B 占 2/4,C 占 1/4
  • weight 只能用在 Row/Column 的直接子项上。
  • 如果某子项没有 weight,它会先根据自身内容大小占据空间,剩下的空间才由带 weight 的子项按比例分配。

2.6 布局修饰符总结

场景 使用
垂直排列多个组件 Column
水平排列多个组件 Row
组件重叠(如徽标、遮罩) Box
按比例分配空间 Modifier.weight()
让组件在父布局中单独对齐 Modifier.align()
让整个布局居中 Box(contentAlignment = Alignment.Center)
posted @ 2026-06-21 19:55  yuansir0731  阅读(6)  评论(0)    收藏  举报