布局基础: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) 覆盖即可。

小技巧:Box 的 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 专用)
核心记忆法:Arrangement 管「怎么排」,Alignment 管「怎么对齐」。排是位置分布,对是方向校准。

四、知识体系结构图

下面这张图,是我自己总结的布局知识体系。你看一眼,心里就有谱了。

Compose 布局知识体系 Column 垂直布局 Row 水平布局 Box 层叠布局 Modifier 修饰符(尺寸、内边距、背景、点击、滚动...) Arrangement 主轴排列 Alignment 交叉轴对齐 Column / Row / Box + Modifier + Arrangement / Alignment

五、实战组合示例

光说不练假把式。我们写一个常见的「用户卡片」布局,把今天学的都用上。

@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 控制排列对齐。嗯,一个完整的卡片就出来了。

避坑指南:我曾经在 Row 里用 Modifier.weight() 时,忘记给 Row 设置 fillMaxWidth(),结果 weight 不生效。记住:weight 需要父容器有明确的主轴尺寸。

六、总结

Column、Row、Box 是 Compose 布局的三大基石。Modifier 是给这些基石「化妆」的工具。Arrangement 和 Alignment 是控制布局「姿势」的两个开关。

你想想看,一个界面无非就是:用 Column 或 Row 把元素排成一行或一列,用 Box 把元素叠起来,再用 Modifier 调整大小、间距、背景、点击事件。就这么简单。

刚开始可能会觉得 Modifier 链式调用有点绕,但用多了你会发现——这比 XML 的嵌套布局清晰多了。至少你不用在十几个 XML 标签里找对应的 layout_width 和 layout_height。

我的建议:打开 Android Studio,新建一个 Compose 项目,把上面的代码敲一遍。然后试着改改 Arrangement 和 Alignment 的值,看看效果。动手试一次,比看十遍文章都管用。

公众号:蓝海资料掘金营,微信deep3321