Row 和 Column 的基本用法
Row 示例(水平排列)
Dart
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.star, color: Colors.yellow),
Text(' 评分: 4.5'),
],
)
Column 示例(垂直排列)
Dart
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text('标题', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
Text('副标题'),
],
)
布局控制属性详解
1. Row / Column 的"坐标系"先搞清楚
1.1 主轴(main axis) vs 交叉轴(cross axis)
-
Row
-
主轴:水平方向(左 ↔ 右)
-
交叉轴:垂直方向(上 ↕ 下)
-
-
Column
-
主轴:垂直方向(上 ↕ 下)
-
交叉轴:水平方向(左 ↔ 右)
-
理解一个关键点:所有 "mainXXX" 控制的是子组件在主轴上的行为;所有 "crossXXX" 控制的是在交叉轴上的行为。
2. mainAxisAlignment:主轴方向"怎么排列"
控制:子组件沿主轴的对齐和间距
Dart
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Icon(Icons.star),
Icon(Icons.star),
Icon(Icons.star),
],
)
枚举值(Row 为例,Column 同理,只是方向变垂直):
start
-
默认值
-
子组件紧挤在主轴 起点
-
Row:靠左;Column:靠上
end
-
子组件紧挤在主轴 终点
-
Row:靠右;Column:靠下
center
- 子组件整体居中,中间挤在一起
spaceBetween
-
首尾贴边,中间元素之间"平均分配间距"
-
典型效果:左一个,右一个,中间均匀散开
spaceAround
-
子组件之间的间距 相等
-
首尾和边界的间距 = 中间间距的一半
-
视觉效果:两边看起来比中间稍紧一点
spaceEvenly
-
所有间距 完全相等(包括首尾到边界)
-
最"对称强迫症"友好的布局
心理模型:
不想管"边距",只想管"元素之间":用
spaceBetween想整体看起来"对称平衡":用
spaceEvenly想两边略紧,中间舒服:用
spaceAround
3. crossAxisAlignment:交叉轴方向"怎么对齐"
控制:子组件在交叉轴上的对齐(垂直对齐 Row,水平对齐 Column)。
Dart
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('短'),
Text('一行很长很长很长的文字'),
],
)
枚举值(常用):
start
沿交叉轴起点对齐
Row:上对齐;Column:左对齐
end
沿交叉轴终点对齐
Row:下对齐;Column:右对齐
center
沿交叉轴居中对齐(默认)
stretch
- 子组件在交叉轴方向被拉伸填满 Row/Column
- 前提:子组件在交叉轴方向不能设置"固定尺寸"(比如
width/height)
示例(Column 中):
Dart
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(height: 40, color: Colors.red),
Container(height: 40, color: Colors.green),
],
)
效果:两个 Container 自动铺满宽度 (等同于 width = double.infinity)
baseline(只对 Row 有意义)
-
按文字基线 对齐,通常与
Text搭配 -
使用时需要指定
textBaseline,否则会报错
Dart
Row(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: const [
Text('Hello', style: TextStyle(fontSize: 30)),
Text('World', style: TextStyle(fontSize: 16)),
],
)
效果:两段文字底部基线对齐,而不是按顶部 / 底部对齐。
4. mainAxisSize:主轴方向"占多大空间"
控制:Row / Column 本身在主轴方向上占用多少空间
默认:MainAxisSize.max
4.1 MainAxisSize.max(默认)
-
Row / Column 尽可能占满主轴可用空间
-
在
Column中,如果子组件是Row(mainAxisSize: max),Row 会横向撑满整行。
Dart
Column(
children: [
Container(color: Colors.grey, height: 200, child: Row(
mainAxisSize: MainAxisSize.max,
children: const [
Text('A'),
Text('B'),
],
)),
],
)
Row 会占满这 200 高容器的宽度。
4.2 MainAxisSize.min
-
Row / Column 在主轴上只包裹子组件所需大小
-
很适合:居中小块内容 + 外层加对齐控制
Dart
Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [
Icon(Icons.favorite),
SizedBox(width: 8),
Text('Like'),
],
),
)
Row 只会围着 Icon + Text 那一小块内容,而不是横向占满整个屏幕。
5. textDirection / verticalDirection:方向"反过来"
有时候你会发现:start 对齐的方向到底是左还是右?上还是下?
答案:跟 textDirection / verticalDirection 有关。
5.1 textDirection
-
控制主轴的"起点"是左还是右,常见于
Row -
常用值:
-
TextDirection.ltr:左 → 右(默认) -
TextDirection.rtl:右 → 左(适配阿拉伯语等)
-
Dart
Row(
textDirection: TextDirection.rtl,
mainAxisAlignment: MainAxisAlignment.start,
children: const [
Text('1'),
Text('2'),
Text('3'),
],
)
此时 start 是"右边",所以 1、2、3 会从 右向左排。
5.2 verticalDirection
-
控制交叉轴的"起点"是上还是下,常见于:
-
Column的主轴(垂直方向) -
交叉轴的对齐 start/end 的含义
-
常用值:
-
VerticalDirection.down(默认):从上往下 -
VerticalDirection.up:从下往上
Dart
Column(
verticalDirection: VerticalDirection.up,
children: const [
Text('A'),
Text('B'),
Text('C'),
],
)
渲染顺序:C 在最上,A 在最下(因为"起点"在下方)。
6. Expanded / Flexible:在主轴上"怎么分配剩余空间"
Row / Column 本身只是"容器",真正控制剩余空间怎么分配 ,要靠 Expanded / Flexible。
6.1 Expanded
-
语义:"把剩余空间都分掉,且子组件必须填满自己的份额"
-
flex用来控制比例
Dart
Row(
children: [
Expanded(
flex: 1,
child: Container(color: Colors.red, height: 50),
),
Expanded(
flex: 2,
child: Container(color: Colors.blue, height: 50),
),
],
)
效果:红:蓝 = 1 : 2 占主轴宽度。
特点:
- 会忽略子组件在主轴方向上的尺寸(比如
width),统一按"平分策略"来分配。
6.2 Flexible
-
语义:"按比例给你一个上限,但你可以比这个小"
-
子组件可以根据自身
width/height需要更小的空间,不强制撑满。
常用写法:
Dart
Row(
children: [
Flexible(
flex: 1,
child: Container(
color: Colors.red,
height: 50,
// 宽度可能小于分配给它的那一份
),
),
const Text('固定大小的文字'),
],
)
Dart
Row(
children: const [
Expanded(child: Center(child: Text('Tab1'))),
Expanded(child: Center(child: Text('Tab2'))),
Expanded(child: Center(child: Text('Tab3'))),
],
)
简单记忆:
-
想让子组件 "铺满自己的份额" →
Expanded -
想让子组件 "最多这么大,多余空间我不一定用完" →
Flexible
6.3 Spacer:只是"占空位"的 Expanded
Dart
Row(
children: const [
Text('左'),
Spacer(), // 等价于 Expanded(flex: 1, child: SizedBox.shrink())
Text('右'),
],
)
用来快速制造"弹簧"空白区域。
7. 常见布局组合示例
7.1 顶部标题 + 右侧操作按钮
Dart
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text('标题', style: TextStyle(fontSize: 18)),
Icon(Icons.more_vert),
],
)
效果:左标题,右按钮,中间自动拉开。
7.2 三等分底部 Tab
Dart
Row(
children: const [
Expanded(child: Center(child: Text('Tab1'))),
Expanded(child: Center(child: Text('Tab2'))),
Expanded(child: Center(child: Text('Tab3'))),
],
)
每个 Tab 自动占 1/3 宽度,居中显示文字。
7.3 内容居中的小块 Tag
Dart
Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.tag),
const SizedBox(width: 4),
const Text('Flutter'),
],
),
)
Row 不会撑满整行,只包裹 Icon + 文字一小块。
7.4 左图 + 右侧标题和描述(典型 ListItem)
Dart
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Icon(Icons.image, size: 40),
const SizedBox(width: 8),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text('标题', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
SizedBox(height: 4),
Text('一段比较长的描述文字......', maxLines: 2, overflow: TextOverflow.ellipsis),
],
),
),
],
)
-
外层 Row 控制左右结构
-
右侧用 Expanded + Column,内部再用 crossAxisAlignment 控制左对齐
8. Row / Column 调试小技巧
-
加背景色看布局范围
DartContainer( color: Colors.yellow.withOpacity(0.2), child: Row(...), ) -
再嵌一层 Container,指定宽高,看"主轴 vs 交叉轴":
DartSizedBox( width: 200, height: 100, child: Container( color: Colors.blue.withOpacity(0.1), child: Row(...), ), ) -
配合
debugPaintSizeEnabled = true(在main()里开启)
可以看到组件的边界线,帮你看清楚到底是谁在撑大 / 撑满。