3、布局基础:Column、Row、Box 三大布局组件、Modifier 的概念与链式调用

各位同学,欢迎来到第三章。这一章我们聊聊 Compose 里最基础、也最核心的东西——布局。

说实话,我刚开始从传统 View 系统转到 Compose 时,最不适应的就是布局方式。以前写 XML,LinearLayout、RelativeLayout、FrameLayout 用得很顺手。到了 Compose 这边,变成了 Column、Row、Box。名字变了,但核心思想其实更简单了。

这一章我会带你彻底搞懂这三个组件,以及那个无处不在的 Modifier。嗯,Modifier 这东西,我第一次看的时候觉得它像个「魔法棒」,后来才发现它其实就是个链式调用的工具。咱们一步步来。

3.1 三大布局组件:Column、Row、Box

先看一张图,帮你快速建立整体认知:

Compose 三大布局组件 Column 垂直排列 子组件 1 子组件 2 子组件 3 Row 水平排列 1 2 3 Box 层叠排列 底层 顶层 垂直方向,从上到下 水平方向,从左到右 Z 轴方向,从后到前

这张图很直观。Column 是垂直堆叠,Row 是水平排列,Box 是层叠(像 FrameLayout)。记住这三个方向,你就能搭出任何界面。

3.2 Column:垂直布局

Column 就是把子组件从上往下排。我在项目中用得最多的是列表页面的整体骨架,比如用户信息页:头像在上,名字在中间,按钮在下面。

@Composable
fun UserProfile() {
    Column(
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(12.dp)
    ) {
        // 头像
        Icon(
            imageVector = Icons.Default.Person,
            contentDescription = "头像",
            modifier = Modifier.size(80.dp),
            tint = MaterialTheme.colorScheme.primary
        )
        // 名字
        Text(text = "张三", style = MaterialTheme.typography.headlineSmall)
        // 按钮
        Button(onClick = { /* 编辑资料 */ }) {
            Text("编辑资料")
        }
    }
}

这里有两个参数要注意:

  • horizontalAlignment:控制子组件在水平方向的对齐方式。默认是 Start(左对齐),常用 CenterHorizontally(居中)。
  • verticalArrangement:控制子组件在垂直方向的排列方式。spacedBy(12.dp) 表示每个子组件之间间隔 12dp。
我的习惯: 只要 Column 里超过两个子组件,我几乎必用 spacedBy。手动加 padding 或 margin 太容易出错了,而且改起来麻烦。spacedBy 一行代码搞定,后期调整间距也快。

3.3 Row:水平布局

Row 和 Column 是对称的。一个水平排,一个垂直排。参数也几乎一样,只是方向不同。

我记得有一次做底部操作栏,三个按钮要水平均匀分布。用 Row 配合 Arrangement.SpaceEvenly,几行代码就搞定了。

@Composable
fun BottomActions() {
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(horizontal = 16.dp),
        horizontalArrangement = Arrangement.SpaceEvenly,
        verticalAlignment = Alignment.CenterVertically
    ) {
        IconButton(onClick = { /* 点赞 */ }) {
            Icon(Icons.Default.ThumbUp, contentDescription = "点赞")
        }
        IconButton(onClick = { /* 评论 */ }) {
            Icon(Icons.Default.Chat, contentDescription = "评论")
        }
        IconButton(onClick = { /* 分享 */ }) {
            Icon(Icons.Default.Share, contentDescription = "分享")
        }
    }
}

Arrangement 有几种常用模式:

模式 效果
Start 从起始位置开始排列
End 从结束位置开始排列
Center 居中排列
SpaceBetween 首尾贴边,中间均匀分布
SpaceEvenly 所有间距(包括首尾)相等
SpaceAround 每个元素两侧间距相等,首尾间距为一半
我曾经踩过的坑: 用 SpaceBetween 时,如果子组件数量少,首尾会贴边,中间留很大空白。比如只有两个按钮,一个在左一个在右,中间空一大块。这时候用 SpaceEvenly 或手动加权重更合适。

3.4 Box:层叠布局

Box 允许子组件在 Z 轴方向叠加。说白了,就是后面的组件可以盖在前面的组件上面。

我经常用 Box 做「徽标」效果——比如一个头像右上角加个小红点。或者做「遮罩层」——图片上面盖一层半透明文字。

@Composable
fun AvatarWithBadge() {
    Box(
        modifier = Modifier.size(64.dp),
        contentAlignment = Alignment.TopEnd
    ) {
        // 底层:头像
        Icon(
            imageVector = Icons.Default.Person,
            contentDescription = "头像",
            modifier = Modifier.size(64.dp),
            tint = MaterialTheme.colorScheme.primary
        )
        // 顶层:小红点
        Box(
            modifier = Modifier
                .size(16.dp)
                .background(Color.Red, CircleShape)
                .border(2.dp, Color.White, CircleShape)
        )
    }
}

contentAlignment 控制子组件的默认对齐方式。上面代码里 TopEnd 表示子组件默认对齐到右上角。但注意,这个对齐只对「没有指定 Modifier.align」的子组件生效。

核心要点: Box 的 contentAlignment 是「默认对齐」,每个子组件可以通过 Modifier.align() 单独覆盖。这在做复杂叠加布局时非常灵活。

3.5 Modifier 的概念与链式调用

好,接下来聊聊 Modifier。这东西是 Compose 里最常用的「工具链」。

你想想看,在传统 View 系统里,你要给一个按钮设置宽高、边距、背景、点击事件,得写好几行代码。在 Compose 里,全通过 Modifier 链式搞定。

@Composable
fun StyledButton() {
    Button(
        onClick = { /* 点击 */ },
        modifier = Modifier
            .fillMaxWidth()
            .padding(16.dp)
            .height(48.dp)
            .background(Color.Blue, RoundedCornerShape(8.dp))
    ) {
        Text("提交")
    }
}

看到没?fillMaxWidth、padding、height、background 全部串在一起。这就是链式调用。

每个 Modifier 函数返回一个新的 Modifier 对象,所以可以一直 . 下去。顺序很重要!

我曾经犯过的错: 先写 padding 再写 background,和先写 background 再写 padding,效果完全不同。前者是「先留白再涂色」,后者是「先涂色再留白」。你想想看,哪个才是你要的效果?我建议你记住一个原则:先尺寸,再边距,最后背景和点击

Modifier 的常用分类:

类别 常用函数 作用
尺寸 fillMaxWidth、height、width、size 控制组件大小
边距 padding、margin(通过 offset) 控制组件间距
背景 background、border 控制组件外观
事件 clickable、pointerInput 控制交互
布局 align、weight、aspectRatio 控制对齐和比例
我的建议: 刚开始学 Modifier 时,不要试图记住所有函数。记住最常用的 10 个就够了:fillMaxWidth、padding、height、width、size、background、border、clickable、align、weight。其他的用到再查。

3.6 组合使用:一个完整的例子

最后,我们把这些知识串起来,做一个简单的「商品卡片」布局。

@Composable
fun ProductCard(productName: String, price: String) {
    Card(
        modifier = Modifier
            .fillMaxWidth()
            .padding(8.dp),
        elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
    ) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(16.dp),
            verticalAlignment = Alignment.CenterVertically
        ) {
            // 商品图片占位
            Box(
                modifier = Modifier
                    .size(80.dp)
                    .background(Color.LightGray, RoundedCornerShape(8.dp)),
                contentAlignment = Alignment.Center
            ) {
                Icon(Icons.Default.Image, contentDescription = "商品图片")
            }
            // 商品信息
            Column(
                modifier = Modifier
                    .weight(1f)
                    .padding(start = 12.dp)
            ) {
                Text(
                    text = productName,
                    style = MaterialTheme.typography.titleMedium
                )
                Spacer(modifier = Modifier.height(4.dp))
                Text(
                    text = price,
                    style = MaterialTheme.typography.bodyLarge,
                    color = MaterialTheme.colorScheme.primary
                )
            }
        }
    }
}

这个例子用了:

  • Card 作为外层容器
  • Row 水平排列图片和文字
  • Box 做图片占位
  • Column 垂直排列商品名和价格
  • Modifier 链式调用控制尺寸、边距、对齐

嗯,到这里你应该对 Column、Row、Box 和 Modifier 有了比较清晰的认识。说白了,布局就是「选对容器 + 用好 Modifier」。多写几次,手感自然就来了。

本章核心总结:
  • Column 垂直排,Row 水平排,Box 层叠排
  • Arrangement 控制排列方式,Alignment 控制对齐方式
  • Modifier 是链式调用的工具,顺序影响最终效果
  • 先尺寸,再边距,最后背景和点击——记住这个顺序
公众号:蓝海资料掘金营,微信deep3321