flutter学习第 4 节:布局基础:Row、Column、Stack

302 阅读5分钟

在 Flutter 中,布局是构建界面的核心。无论多么复杂的界面,都是由基础布局组件组合而成。本节课我们将详细讲解 Flutter 中最常用的布局组件,包括线性布局(Row/Column)、层叠布局(Stack)以及辅助布局组件,帮助你掌握界面搭建的基础能力。

一、线性布局:Row 与 Column

线性布局是最常用的布局方式,通过水平方向(Row)  或垂直方向(Column)  排列子组件。

1. Row:水平排列子组件

Row 组件用于在水平方向上排列子组件,它的构造函数简化如下:

Row({
  Key? key,
  MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, // 主轴对齐方式
  CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, // 交叉轴对齐方式
  MainAxisSize mainAxisSize = MainAxisSize.max, // 主轴尺寸(占满父组件还是包裹子组件)
  VerticalDirection verticalDirection = VerticalDirection.down, // 垂直方向排序
  TextDirection? textDirection, // 水平方向排序(影响 start/end 的判断)
  List<Widget> children = const [], // 子组件列表
})

示例代码

Row(
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Container(width: 60, height: 60, color: Colors.green),
    Container(width: 70, height: 70, color: Colors.blue),
  ],
)

运行后会看到三个颜色块在水平方向依次排列。

2. Column:垂直排列子组件

Column 与 Row 用法完全一致,唯一区别是垂直方向排列子组件

Column(
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Container(width: 60, height: 60, color: Colors.green),
    Container(width: 70, height: 70, color: Colors.blue),
  ],
)

3. 主轴与交叉轴

理解主轴交叉轴是掌握线性布局的关键:

  • 主轴:组件排列的方向

    • Row 的主轴是水平方向(左右)
    • Column 的主轴是垂直方向(上下)
  • 交叉轴:与主轴垂直的方向

    • Row 的交叉轴是垂直方向(上下)
    • Column 的交叉轴是水平方向(左右)


二、对齐方式:MainAxisAlignment 与 CrossAxisAlignment

通过对齐方式可以精确控制子组件在主轴和交叉轴上的位置。

1. 主轴对齐(MainAxisAlignment)

控制子组件在主轴上的排列方式,常用值包括:

  • start:沿主轴起点对齐(Row 左对齐,Column 上对齐)
  • end:沿主轴终点对齐(Row 右对齐,Column 下对齐)
  • center:主轴居中对齐
  • spaceBetween:子组件之间平均分配空间(两端组件顶边)
  • spaceAround:子组件两侧均匀分配空间(两端空间是中间的一半)
  • spaceEvenly:所有空间(包括两端)平均分配

示例(Row + spaceBetween)

Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Container(width: 50, height: 50, color: Colors.green),
    Container(width: 50, height: 50, color: Colors.blue),
  ],
)

2. 交叉轴对齐(CrossAxisAlignment)

控制子组件在交叉轴上的排列方式,常用值包括:

  • start:沿交叉轴起点对齐
  • end:沿交叉轴终点对齐
  • center:交叉轴居中对齐(默认值)
  • stretch:子组件拉伸至填满交叉轴(需子组件无固定尺寸)
  • baseline:按基线对齐(仅 Row 有效,与文字基线相关)

示例(Row + stretch)

Row(
  crossAxisAlignment: CrossAxisAlignment.stretch, // 垂直方向拉伸
  children: [
    Container(width: 50, color: Colors.red), // 不指定高度,会被拉伸
    Container(width: 50, height: 60, color: Colors.green),
    Container(width: 50, height: 70, color: Colors.blue),
  ],
)


三、层叠布局:Stack 与 Positioned

当需要子组件堆叠显示(如图片上叠加文字)时,使用 Stack 与 Positioned 组合。

1. Stack:堆叠子组件

Stack 会将子组件按顺序堆叠(后添加的组件在上方),构造函数简化如下:

Stack({
  Key? key,
  AlignmentGeometry alignment = Alignment.center, // 未定位子组件的对齐方式
  TextDirection? textDirection,
  StackFit fit = StackFit.loose, // 子组件尺寸适配方式
  Clip clipBehavior = Clip.hardEdge, // 超出范围是否裁剪
  List<Widget> children = const [],
})

基础示例

Stack(
  children: [
    // 底层红色容器
    Container(width: 200, height: 200, color: Colors.red),
    // 中间绿色容器(叠在红色上)
    Container(width: 150, height: 150, color: Colors.green),
    // 顶层蓝色容器(叠在最上面)
    Container(width: 100, height: 100, color: Colors.blue),
  ],
)

2. Positioned:定位子组件

Positioned 用于在 Stack 中精确定位子组件,必须作为 Stack 的直接子组件使用,常用属性:

  • left:距离 Stack 左边缘的距离
  • right:距离 Stack 右边缘的距离
  • top:距离 Stack 上边缘的距离
  • bottom:距离 Stack 下边缘的距离
  • width/height:指定子组件的宽高(可选)

示例

Stack(
  children: [
    Container(width: 200, height: 200, color: Colors.grey),
    // 左上角定位
    Positioned(
      left: 10,
      top: 10,
      child: Container(width: 50, height: 50, color: Colors.red),
    ),
    // 右下角定位
    Positioned(
      right: 10,
      bottom: 10,
      child: Container(width: 50, height: 50, color: Colors.blue),
    ),
  ],
)


四、常用布局辅助 Widget

这些组件本身不负责布局,但能辅助调整子组件的位置、尺寸等。

1. Padding:内边距

为子组件添加内边距(子组件与父容器边缘的距离):

Padding(
  padding: EdgeInsets.all(16), // 四个方向都添加16px内边距
  // 也可以单独设置:EdgeInsets.only(left: 10, top: 20)
  child: Container(width: 100, height: 100, color: Colors.red),
)

EdgeInsets 常用构造:

  • all(value):四边统一值
  • only(left, top, right, bottom):单独设置
  • symmetric(horizontal, vertical):水平 / 垂直对称设置

2. Margin:外边距

Flutter 中没有单独的 Margin 组件,通过 Container 的 margin 属性实现(子组件与其他组件的距离):

Container(
  margin: EdgeInsets.all(10), // 外边距
  padding: EdgeInsets.all(10), // 内边距
  color: Colors.grey,
  child: Container(width: 50, height: 50, color: Colors.red),
)

3. Center:居中对齐

简化版的对齐组件,等价于 Align(alignment: Alignment.center, child: ...)

Center(
  child: Container(width: 100, height: 100, color: Colors.green),
)

4. Expanded:占满剩余空间

在 Row 或 Column 中,Expanded 会让子组件占满主轴方向的剩余空间,解决子组件总宽度 / 高度超出父组件的问题(溢出会报黄线错误)。

基础用法

Row(
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Expanded(
      // 占满剩余空间
      child: Container(height: 50, color: Colors.green),
    ),
    Container(width: 50, height: 50, color: Colors.blue),
  ],
)
Row(
  children: [
    Expanded(
      flex: 1, // 占1份
      child: Container(height: 50, color: Colors.red),
    ),
    Expanded(
      flex: 2, // 占2份(总空间分为3份)
      child: Container(height: 50, color: Colors.green),
    ),
  ],
)


五、综合示例:组合布局

实际开发中,布局组件通常需要嵌套使用。以下是一个简单的用户信息卡片示例:

Container(
  width: 300,
  padding: EdgeInsets.all(16),
  decoration: BoxDecoration(
    color: Colors.white,
    borderRadius: BorderRadius.circular(8),
    boxShadow: [BoxShadow(color: Colors.grey, blurRadius: 3)],
  ),
  child: Row(
    // 水平排列头像和信息
    children: [
      // 头像
      Container(
        width: 60,
        height: 60,
        decoration: BoxDecoration(
          color: Colors.blue,
          borderRadius: BorderRadius.circular(30),
        ),
      ),
      SizedBox(width: 12), // 间距
      // 信息区域(垂直排列)
      Expanded(
        // 占满剩余宽度
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start, // 左对齐
          children: [
            Text(
              "张三",
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
            ),
            SizedBox(height: 4),
            Text("Flutter 开发者", style: TextStyle(color: Colors.grey)),
          ],
        ),
      ),
      // 右侧箭头
      Icon(Icons.arrow_right, color: Colors.grey),
    ],
  ),
)