在Jetpack Compose出现之前,Android开发者习惯用XML文件描述界面结构,通过LinearLayout、FrameLayout、RelativeLayout等容器组合出复杂布局。而Compose把这些容器换成了三个函数:Row、Column和Box。它们看起来简单,但几乎所有的界面结构最终都能拆解成这三种组合。本文将围绕这三个基础组件展开,讲清楚它们的参数含义、排列规则以及常见的组合技巧。

Row:水平排列的容器
Row的作用是把子元素按从左到右的顺序水平排列,可以类比传统View体系中的横向LinearLayout。它的函数签名中有几个关键参数需要掌握:horizontalArrangement控制子元素在水平方向上的分布方式,verticalAlignment控制子元素在垂直方向上的对齐方式。
下面是一段基础用法的示例代码:
@Composable
fun RowDemo() {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(text = "左侧")
Text(text = "中间")
Text(text = "右侧")
}
}
代码中Arrangement.SpaceBetween让三个文本均匀分布,首个元素贴左边,末尾元素贴右边,中间元素居中。这种写法在实现顶部栏、底部导航栏时非常常见,比XML时代写layout_weight和gravity简洁不少。
除了SpaceBetween,Arrangement还提供了Center、SpaceAround、SpaceEvenly、Start、End等选项,另外可以通过Arrangement.spacedBy(16.dp)快速设置子元素之间的固定间距,这是实际项目里使用频率最高的写法之一。
Column:垂直排列的容器
Column与Row正好相反,它把子元素按从上到下的顺序垂直排列,对应传统View体系中的纵向LinearLayout。参数结构也和Row对称:verticalArrangement控制垂直方向的分布,horizontalAlignment控制水平方向的对齐。
看一个典型的列表项布局示例:
@Composable
fun ListItemDemo(title: String, subtitle: String) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
Text(text = title, style = MaterialTheme.typography.titleMedium)
Text(
text = subtitle,
style = MaterialTheme.typography.bodySmall,
color = Color.Gray
)
}
}
这个例子展示了最常见的“标题加副标题”结构,spacedBy(4.dp)让两行文本之间保持固定间距,省去了给每个子元素单独设置margin的麻烦。需要注意,Compose中没有margin的概念,一律使用Modifier.padding,它在容器内部留白,行为上等同于原生的内边距。
Column还支持权重分配。在ColumnScope中调用Modifier.weight(1f),可以让某个子元素填满剩余的垂直空间。比如表单页面中让按钮始终贴在底部,就可以给上方内容区域加上weight修饰符,这种技巧在适配不同屏幕高度时特别实用。
Box:层叠布局的容器
Box允许子元素互相叠加,对应传统View体系中的FrameLayout。它的核心参数是contentAlignment,一次性决定所有子元素的对齐位置;如果每个子元素需要不同的对齐方式,可以在BoxScope中使用Modifier.align()单独指定。
@Composable
fun BoxDemo() {
Box(
modifier = Modifier
.size(200.dp)
.background(Color.LightGray)
) {
Text(text = "居中文字", modifier = Modifier.align(Alignment.Center))
Text(text = "左上角", modifier = Modifier.align(Alignment.TopStart))
Text(text = "右下角", modifier = Modifier.align(Alignment.BottomEnd))
}
}
Box最常见的场景是给图片加蒙层和文字,例如封面图上叠加播放按钮或渐变遮罩。这类需求在XML里要靠FrameLayout加foreground实现,而Compose里只需在Box中先放Image再放内容,代码结构一目了然。
另外要注意Box的测量规则:默认情况下Box会尽量缩小自己以包裹内容,如果希望子元素铺满整个Box,可以给子元素加上Modifier.matchParentSize()。这个修饰符只在BoxScope中可用,和fillMaxSize()的区别在于它不会参与父容器的尺寸测量,能避免一些不必要的布局抖动。
三个组件的组合实战
真实的界面往往是三个容器嵌套使用。以一个简单的视频卡片为例:最外层用Column做整体垂直结构,上半部分用Box叠加封面图和时长标签,下半部分用Row排列头像和标题信息。
@Composable
fun VideoCard(title: String) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
) {
Box {
Image(
painter = painterResource(id = R.drawable.cover),
contentDescription = null,
modifier = Modifier
.fillMaxWidth()
.height(120.dp)
)
Text(
text = "03:25",
modifier = Modifier
.align(Alignment.BottomEnd)
.padding(4.dp)
.background(Color.Black.copy(alpha = 0.6f))
.padding(horizontal = 4.dp)
.color(Color.White),
fontSize = 12.sp
)
}
Row(
modifier = Modifier.padding(top = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(text = "UP主名称", fontSize = 12.sp)
Text(text = title, fontSize = 14.sp, maxLines = 1)
}
}
}
从这个例子可以看出Compose布局思路的本质:把界面拆成一个个小的组合函数,每个容器只负责一件事。相比XML,这种方式的优点是布局结构即代码结构,复用时直接调用函数即可,不需要include标签,也不存在merge优化的问题。
需要提醒的是,嵌套层级并不是越多越好。Compose虽然对深层嵌套的容忍度比传统View高,但每一层容器都有测量开销,写布局时应该优先考虑用Modifier的链式调用来替代不必要的嵌套。例如一个元素需要内边距加背景色加圆角,直接链式调用padding、background、clip即可完成,不必为了分组而额外包一层容器。掌握好Row、Column、Box这三块基石,再配合Modifier体系,就能应对绝大多数界面布局需求了。
Jetpack ComposeCompose布局Row Column Box修改时间:2026-09-15 11:24:34