布局基础:Column、Row、Box 三大布局组件,Modifier 修饰符详解,对齐与排列方式
说实话,刚接触 Jetpack Compose 的时候,我最大的困惑就是——怎么把东西摆在屏幕上?
以前写 XML 布局,LinearLayout、RelativeLayout、FrameLayout 用得很顺手。到了 Compose 这边,一切变成了函数调用。嗯,其实思路没变,只是写法换了。今天我们就来聊聊 Compose 里的三大布局组件:Column、Row、Box,以及它们的灵魂伴侣——Modifier。
一、三大布局组件:Column、Row、Box
这三个组件,说白了就是 Android 传统布局的「函数式版本」:
- Column:垂直排列子元素,相当于 LinearLayout 的 vertical 方向
- Row:水平排列子元素,相当于 LinearLayout 的 horizontal 方向
- Box:子元素可以重叠,相当于 FrameLayout
我个人习惯把 Column 和 Row 叫做「线性布局兄弟」,Box 叫「叠罗汉布局」。你想想看,日常开发中 90% 的界面,用这三个组合就能搞定。
1. Column 垂直布局
@Composable
fun ColumnExample() {
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("第一行")
Text("第二行")
Text("第三行")
}
}
我在项目中遇到过一个问题:Column 里的内容太多,超出屏幕了怎么办?默认情况下它会继续绘制,导致底部内容被截断。加上 Modifier.verticalScroll(rememberScrollState()) 就能滚动。
2. Row 水平布局
@Composable
fun RowExample() {
Row(
modifier = Modifier.fillMaxWidth().padding(8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Icon(Icons.Default.Home, contentDescription = "首页")
Text("中间标题")
Icon(Icons.Default.Settings, contentDescription = "设置")
}
}
Row 的用法和 Column 几乎对称。一个管水平方向,一个管垂直方向。记住:Arrangement 是主轴方向的对齐,Alignment 是交叉轴方向的对齐。这个搞混了,布局就会乱。
3. Box 层叠布局
@Composable
fun BoxExample() {
Box(
modifier = Modifier.size(200.dp),
contentAlignment = Alignment.Center
) {
Image(
painter = painterResource(id = R.drawable.bg),
contentDescription = "背景",
modifier = Modifier.fillMaxSize()
)
Text(
text = "浮在图片上的文字",
color = Color.White,
fontSize = 20.sp
)
}
}
Box 的 contentAlignment 控制所有子元素的默认对齐方式。如果你想让某个子元素单独对齐,用 Modifier.align(Alignment.TopEnd) 覆盖即可。
Modifier.matchParentSize() 可以让子元素和 Box 一样大,常用于占位或背景层。
二、Modifier 修饰符详解
Modifier 是 Compose 里最核心的概念之一。它就像 XML 里的 layout_xxx 属性,但更强大、更灵活。说白了,Modifier 就是一组「装饰器」,你可以链式调用,按顺序应用。
常用 Modifier 分类
| 类别 | 常用 Modifier | 说明 |
|---|---|---|
| 尺寸 | size(), width(), height(), fillMaxSize() |
控制组件大小 |
| 内边距 | padding(), paddingFrom() |
设置内边距 |
| 外边距 | offset(), margin()(需扩展) |
偏移位置 |
| 背景 | background(), border() |
设置背景色、边框 |
| 点击 | clickable(), pointerInput() |
处理点击事件 |
| 滚动 | verticalScroll(), horizontalScroll() |
使组件可滚动 |
我曾经踩过一个坑:Modifier 的顺序很重要!比如 Modifier.clickable{}.padding(16.dp) 和 Modifier.padding(16.dp).clickable{},点击区域完全不同。前者点击区域包含内边距,后者只点击内容区域。嗯,这个细节很容易被忽略。
Modifier 链式调用示例
@Composable
fun ModifierChainExample() {
Text(
text = "点我试试",
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
.background(Color.LightGray, shape = RoundedCornerShape(8.dp))
.padding(12.dp)
.clickable { /* 处理点击 */ }
.border(2.dp, Color.Blue, shape = RoundedCornerShape(8.dp))
)
}
注意看:我用了两次 padding()。第一次是给整个组件加外边距,第二次是给文字加内边距。这种「嵌套 padding」的技巧,在复杂布局中非常实用。
三、对齐与排列方式
对齐和排列,是布局的灵魂。Compose 里主要靠两个参数控制:
- Arrangement:主轴方向上的排列方式
- Alignment:交叉轴方向上的对齐方式
举个例子:Column 的主轴是垂直方向,交叉轴是水平方向。所以 verticalArrangement 控制垂直排列,horizontalAlignment 控制水平对齐。
Arrangement 常用值
| 值 | 效果 |
|---|---|
Start |
从主轴起点开始排列 |
End |
从主轴终点开始排列 |
Center |
居中排列 |
SpaceBetween |
两端对齐,中间间距相等 |
SpaceAround |
每个元素两侧间距相等 |
SpaceEvenly |
所有间距(包括两端)相等 |
Alignment 常用值
| 值 | 效果 |
|---|---|
Start |
交叉轴起点对齐 |
End |
交叉轴终点对齐 |
Center |
交叉轴居中对齐 |
Top |
顶部对齐(Row 专用) |
Bottom |
底部对齐(Row 专用) |
四、知识体系结构图
下面这张图,是我自己总结的布局知识体系。你看一眼,心里就有谱了。
五、实战组合示例
光说不练假把式。我们写一个常见的「用户卡片」布局,把今天学的都用上。
@Composable
fun UserCard(name: String, avatar: String, desc: String) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(12.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
// 头像区域(用 Box 模拟)
Box(
modifier = Modifier
.size(60.dp)
.background(Color.Gray, shape = CircleShape),
contentAlignment = Alignment.Center
) {
Text(text = name.take(1), color = Color.White, fontSize = 24.sp)
}
Spacer(modifier = Modifier.width(16.dp))
// 文字信息区域(用 Column)
Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.Center
) {
Text(text = name, fontWeight = FontWeight.Bold, fontSize = 18.sp)
Spacer(modifier = Modifier.height(4.dp))
Text(text = desc, color = Color.Gray, fontSize = 14.sp)
}
// 右侧图标
Icon(
Icons.Default.ArrowForward,
contentDescription = "更多",
tint = Color.Gray
)
}
}
}
这个例子里,Row 做水平布局,Column 做垂直布局,Box 做头像的圆形裁剪和文字居中。Modifier 链式调用控制尺寸、内边距、背景。Arrangement 和 Alignment 控制排列对齐。嗯,一个完整的卡片就出来了。
Modifier.weight() 时,忘记给 Row 设置 fillMaxWidth(),结果 weight 不生效。记住:weight 需要父容器有明确的主轴尺寸。
六、总结
Column、Row、Box 是 Compose 布局的三大基石。Modifier 是给这些基石「化妆」的工具。Arrangement 和 Alignment 是控制布局「姿势」的两个开关。
你想想看,一个界面无非就是:用 Column 或 Row 把元素排成一行或一列,用 Box 把元素叠起来,再用 Modifier 调整大小、间距、背景、点击事件。就这么简单。
刚开始可能会觉得 Modifier 链式调用有点绕,但用多了你会发现——这比 XML 的嵌套布局清晰多了。至少你不用在十几个 XML 标签里找对应的 layout_width 和 layout_height。
公众号:蓝海资料掘金营,微信deep3321