Flutter弹性布局 #

一、Flex #

1.1 基本概念 #

Flex是Row和Column的底层实现,通过direction属性控制方向。

dart
Flex({
  Key? key,
  required Axis direction,
  MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
  MainAxisSize mainAxisSize = MainAxisSize.max,
  CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
  TextDirection? textDirection,
  VerticalDirection verticalDirection = VerticalDirection.down,
  TextBaseline? textBaseline,
  Clip clipBehavior = Clip.none,
  List<Widget> children = const <Widget>[],
})

Flex(
  direction: Axis.horizontal,
  children: [
    Expanded(child: Container(color: Colors.red)),
    Expanded(child: Container(color: Colors.green)),
  ],
)

1.2 Flex方向 #

dart
Axis.horizontal
Axis.vertical

1.3 Flex与Row/Column的关系 #

dart
Row(children: [...])
Flex(direction: Axis.horizontal, children: [...])

Column(children: [...])
Flex(direction: Axis.vertical, children: [...])

二、Expanded详解 #

2.1 工作原理 #

Expanded会强制子Widget填满父Widget的剩余空间。

dart
Expanded({
  Key? key,
  int flex = 1,
  Widget? child,
})

2.2 flex属性 #

flex属性决定了子Widget在剩余空间中的比例:

dart
Row(
  children: [
    Expanded(
      flex: 1,
      child: Container(height: 100, color: Colors.red),
    ),
    Expanded(
      flex: 2,
      child: Container(height: 100, color: Colors.green),
    ),
    Expanded(
      flex: 3,
      child: Container(height: 100, color: Colors.blue),
    ),
  ],
)

2.3 常见用法 #

等分空间:

dart
Row(
  children: [
    Expanded(child: Container(height: 100, color: Colors.red)),
    Expanded(child: Container(height: 100, color: Colors.green)),
    Expanded(child: Container(height: 100, color: Colors.blue)),
  ],
)

固定+弹性:

dart
Row(
  children: [
    Container(width: 100, height: 100, color: Colors.red),
    Expanded(child: Container(height: 100, color: Colors.green)),
    Container(width: 100, height: 100, color: Colors.blue),
  ],
)

三栏布局:

dart
Row(
  children: [
    Container(width: 200, height: 100, color: Colors.red),
    Expanded(child: Container(height: 100, color: Colors.green)),
    Container(width: 200, height: 100, color: Colors.blue),
  ],
)

三、Flexible详解 #

3.1 工作原理 #

Flexible允许子Widget根据内容大小或flex比例来分配空间。

dart
Flexible({
  Key? key,
  int flex = 1,
  FlexFit fit = FlexFit.loose,
  Widget? child,
})

3.2 FlexFit属性 #

说明
FlexFit.tight 强制填满空间(同Expanded)
FlexFit.loose 可以小于分配的空间
dart
Row(
  children: [
    Flexible(
      flex: 1,
      fit: FlexFit.tight,
      child: Container(height: 100, color: Colors.red),
    ),
    Flexible(
      flex: 1,
      fit: FlexFit.loose,
      child: Container(width: 50, height: 100, color: Colors.green),
    ),
  ],
)

3.3 Expanded vs Flexible #

dart
Column(
  children: [
    Text('Expanded - 填满剩余空间'),
    Row(
      children: [
        Expanded(
          child: Container(
            height: 50,
            color: Colors.red,
            child: Center(child: Text('Expanded')),
          ),
        ),
      ],
    ),
    SizedBox(height: 16),
    Text('Flexible - 可以不填满'),
    Row(
      children: [
        Flexible(
          child: Container(
            width: 100,
            height: 50,
            color: Colors.green,
            child: Center(child: Text('Flexible')),
          ),
        ),
      ],
    ),
  ],
)

四、Spacer #

4.1 基本用法 #

Spacer是Expanded的简化版本,专门用于创建空白空间。

dart
Row(
  children: [
    Text('Left'),
    Spacer(),
    Text('Right'),
  ],
)

4.2 flex属性 #

dart
Row(
  children: [
    Text('Left'),
    Spacer(flex: 2),
    Text('Middle'),
    Spacer(flex: 1),
    Text('Right'),
  ],
)

4.3 Spacer与Expanded的关系 #

dart
Spacer()
Expanded(child: SizedBox())

五、实战示例 #

5.1 底部按钮栏 #

dart
Container(
  padding: EdgeInsets.all(16),
  child: Row(
    children: [
      Expanded(
        child: OutlinedButton(
          onPressed: () {},
          child: Text('Cancel'),
        ),
      ),
      SizedBox(width: 16),
      Expanded(
        child: ElevatedButton(
          onPressed: () {},
          child: Text('Confirm'),
        ),
      ),
    ],
  ),
)

5.2 响应式布局 #

dart
LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth > 600) {
      return Row(
        children: [
          Expanded(
            flex: 1,
            child: Container(color: Colors.red),
          ),
          Expanded(
            flex: 2,
            child: Container(color: Colors.green),
          ),
        ],
      );
    } else {
      return Column(
        children: [
          Expanded(
            child: Container(color: Colors.red),
          ),
          Expanded(
            flex: 2,
            child: Container(color: Colors.green),
          ),
        ],
      );
    }
  },
)

5.3 网格布局 #

dart
Column(
  children: [
    Expanded(
      child: Row(
        children: [
          Expanded(child: Container(color: Colors.red)),
          Expanded(child: Container(color: Colors.green)),
        ],
      ),
    ),
    Expanded(
      child: Row(
        children: [
          Expanded(child: Container(color: Colors.blue)),
          Expanded(child: Container(color: Colors.yellow)),
        ],
      ),
    ),
  ],
)

5.4 仪表盘布局 #

dart
Column(
  children: [
    Expanded(
      flex: 2,
      child: Container(
        color: Colors.blue,
        child: Center(child: Text('Main Content')),
      ),
    ),
    Expanded(
      child: Row(
        children: [
          Expanded(
            child: Container(
              color: Colors.red,
              child: Center(child: Text('Stats 1')),
            ),
          ),
          Expanded(
            child: Container(
              color: Colors.green,
              child: Center(child: Text('Stats 2')),
            ),
          ),
          Expanded(
            child: Container(
              color: Colors.orange,
              child: Center(child: Text('Stats 3')),
            ),
          ),
        ],
      ),
    ),
  ],
)

六、性能优化 #

6.1 避免过度嵌套 #

dart
Column(
  children: [
    Expanded(child: Container(color: Colors.red)),
    Expanded(child: Container(color: Colors.green)),
  ],
)

6.2 使用const #

dart
Row(
  children: const [
    Expanded(child: SizedBox(height: 100)),
    Expanded(child: SizedBox(height: 100)),
  ],
)

6.3 避免不必要的Flexible #

dart
Row(
  children: [
    Container(width: 100, color: Colors.red),
    Container(width: 100, color: Colors.green),
  ],
)

七、总结 #

7.1 Widget对比 #

Widget 特点
Flex 底层实现,可设置方向
Expanded 强制填满剩余空间
Flexible 可以不填满空间
Spacer 创建空白空间

7.2 下一步 #

掌握了弹性布局后,让我们学习 流式布局

最后更新:2026-03-28