Flutter 组件:Row / Column

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

  1. 子组件在交叉轴方向被拉伸填满 Row/Column
  2. 前提:子组件在交叉轴方向不能设置"固定尺寸"(比如 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 调试小技巧

  1. 加背景色看布局范围

    Dart 复制代码
    Container(
      color: Colors.yellow.withOpacity(0.2),
      child: Row(...),
    )
  2. 再嵌一层 Container,指定宽高,看"主轴 vs 交叉轴":

    Dart 复制代码
    SizedBox(
      width: 200,
      height: 100,
      child: Container(
        color: Colors.blue.withOpacity(0.1),
        child: Row(...),
      ),
    )
  3. 配合 debugPaintSizeEnabled = true (在 main() 里开启)
    可以看到组件的边界线,帮你看清楚到底是谁在撑大 / 撑满。

相关推荐
2601_949970691 分钟前
HumanizeDuration 跨端三方库仓颉适配全流程
前端·javascript·flutter
传奇开心果编程1 小时前
【Flutter踩坑排雷】第3课:const 误用坑|const 错误使用引发 UI 异常与性能损耗
flutter·移动开发·跨平台·dart·编程语言理论·编程框架·声明式ui
程序员老刘4 小时前
你的Flutter项目要不要紧急升级3.47.8?
flutter·客户端
Talyra426 小时前
不想开会员,我写了一个记账 App
flutter
2601_9495758610 小时前
JSON5 跨端三方库仓颉适配全流程
前端·javascript·flutter
法的空间10 小时前
AI 编程时代,为什么 Dart 分析会拖慢大型项目的开发
android·flutter·ios
恋猫de小郭12 小时前
Flutter 紧急发布 3.47.8 安全升级版本,建议都升级
android·前端·flutter
好的佩奇1 天前
Dart 之模式
android·flutter·dart
淡淡的香烟1 天前
Flutter实现多语言切换
android·flutter·1024程序员节
事圆则缓1 天前
从零搭建一套 Flutter 架构:先跑通数据流
flutter