flutter组件学习之Flex / Expanded弹性布局组件

Flutter 弹性布局组件详解

弹性布局是 Flutter 中最重要的布局方式之一,通过 RowColumnFlexExpandedFlexible 组件,可以创建灵活的自适应界面。

一、核心组件

1. Row - 水平弹性布局

dart 复制代码
Row(
mainAxisAlignment: MainAxisAlignment.start,// 主轴对齐方式
crossAxisAlignment: CrossAxisAlignment.center,// 交叉轴对齐方式
mainAxisSize: MainAxisSize.max,// 主轴尺寸
textDirection: TextDirection.ltr,// 文字方向
verticalDirection: VerticalDirection.down,// 垂直方向
children: <Widget>[
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. Column - 垂直弹性布局

dart 复制代码
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch, // 交叉轴拉伸
children: <Widget>[
Container(height: 50, color: Colors.red),
Container(height: 100, color: Colors.green),
Container(height: 150, color: Colors.blue),
],
)

二、主轴对齐方式详解

dart 复制代码
Column(
children: [
// 1. 起始对齐 (默认)
Container(
height: 100,
color: Colors.grey[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [RedBox(), GreenBox(), BlueBox()],
),
),

SizedBox(height: 10),

// 2. 居中对齐
Container(
height: 100,
color: Colors.grey[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [RedBox(), GreenBox(), BlueBox()],
),
),

SizedBox(height: 10),

// 3. 末尾对齐
Container(
height: 100,
color: Colors.grey[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [RedBox(), GreenBox(), BlueBox()],
),
),

SizedBox(height: 10),

// 4. 均匀分布 - 两端对齐
Container(
height: 100,
color: Colors.grey[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [RedBox(), GreenBox(), BlueBox()],
),
),

SizedBox(height: 10),

// 5. 均匀分布 - 环绕对齐
Container(
height: 100,
color: Colors.grey[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [RedBox(), GreenBox(), BlueBox()],
),
),

SizedBox(height: 10),

// 6. 完全均匀分布
Container(
height: 100,
color: Colors.grey[200],
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [RedBox(), GreenBox(), BlueBox()],
),
),
],
)

// 辅助组件
Widget RedBox() => Container(width: 50, height: 50, color: Colors.red);
Widget GreenBox() => Container(width: 50, height: 50, color: Colors.green);
Widget BlueBox() => Container(width: 50, height: 50, color: Colors.blue);

三、交叉轴对齐方式详解

dart 复制代码
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 1. 起始对齐
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [Text('Start'), Container(width: 100, height: 30, color: Colors.red)],
),

SizedBox(width: 20),

// 2. 居中对齐
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [Text('Center'), Container(width: 100, height: 30, color: Colors.green)],
),

SizedBox(width: 20),

// 3. 末尾对齐
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [Text('End'), Container(width: 100, height: 30, color: Colors.blue)],
),

SizedBox(width: 20),

// 4. 拉伸对齐
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [Text('Stretch'), Container(height: 30, color: Colors.orange)],
),

SizedBox(width: 20),

// 5. 基线对齐
Column(
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text('Baseline', style: TextStyle(fontSize: 16)),
Text('Align', style: TextStyle(fontSize: 24)),
],
),
],
)

四、Expanded 与 Flexible

1. Expanded - 强制填满剩余空间

dart 复制代码
Row(
children: [
// 固定宽度
Container(width: 100, height: 100, color: Colors.red),

// Expanded 填满剩余空间
Expanded(
flex: 2,// 占比 2/3
child: Container(height: 100, color: Colors.green),
),

Expanded(
flex: 1,// 占比 1/3
child: Container(height: 100, color: Colors.blue),
),
],
)

2. Flexible - 灵活的空间占用

dart 复制代码
Row(
children: [
// fit: FlexFit.tight - 类似 Expanded
Flexible(
flex: 1,
fit: FlexFit.tight,// 强制填满
child: Container(height: 50, color: Colors.red),
),

// fit: FlexFit.loose - 按需占用
Flexible(
flex: 1,
fit: FlexFit.loose,// 按需占用
child: Container(
height: 30,// 实际高度30,不会强制填满
color: Colors.green,
),
),

Flexible(
flex: 1,
child: Container(height: 70, color: Colors.blue),
),
],
)

五、Flex 组件(Row/Column 的底层)

dart 复制代码
// Flex 是 Row 和 Column 的底层实现
Flex(
direction: Axis.horizontal,// 或 Axis.vertical
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
// 可以在 Flex 中混合使用 Expanded 和普通组件
Container(width: 50, height: 50, color: Colors.red),
Expanded(
child: Container(height: 50, color: Colors.green),
),
Flexible(
fit: FlexFit.loose,
child: Container(width: 30, height: 50, color: Colors.blue),
),
],
)

六、实战应用示例

1. 响应式布局

dart 复制代码
class ResponsiveLayout extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
// 大屏幕:水平布局
return Row(
children: [
// 侧边栏
Container(
width: 200,
color: Colors.grey[200],
child: ListView(
children: List.generate(10, (i) => ListTile(title: Text('Item $i'))),
),
),
// 主内容
Expanded(
child: Container(
color: Colors.white,
child: Center(child: Text('Main Content')),
),
),
],
);
} else {
// 小屏幕:垂直布局
return Column(
children: [
// 顶部导航
Container(
height: 56,
color: Colors.grey[200],
child: Center(child: Text('Mobile Navigation')),
),
// 主内容
Expanded(
child: Container(
color: Colors.white,
child: ListView(
children: List.generate(20, (i) => ListTile(title: Text('Item $i'))),
),
),
),
],
);
}
},
);
}
}

2. 表格布局

dart 复制代码
Column(
children: [
// 表头
Row(
children: [
Expanded(flex: 2, child: TableHeader('Name')),
Expanded(flex: 1, child: TableHeader('Age')),
Expanded(flex: 1, child: TableHeader('Score')),
],
),
Divider(height: 1),
// 表格内容
Expanded(
child: ListView.builder(
itemCount: 10,
itemBuilder: (context, index) {
return TableRowItem(index: index);
},
),
),
],
)

class TableHeader extends StatelessWidget {
final String title;
TableHeader(this.title);

@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(12),
color: Colors.grey[100],
child: Text(title, style: TextStyle(fontWeight: FontWeight.bold)),
);
}
}

class TableRowItem extends StatelessWidget {
final int index;
TableRowItem({required this.index});

@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
flex: 2,
child: Container(
padding: EdgeInsets.all(12),
child: Text('User $index'),
),
),
Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.all(12),
child: Text('${20 + index}'),
),
),
Expanded(
flex: 1,
child: Container(
padding: EdgeInsets.all(12),
child: Text('${80 + index}'),
),
),
],
);
}
}

3. 流式标签布局

dart 复制代码
class TagFlowLayout extends StatefulWidget {
@override
_TagFlowLayoutState createState() => _TagFlowLayoutState();
}

class _TagFlowLayoutState extends State<TagFlowLayout> {
final tags = [
'Flutter', 'Dart', 'Mobile', 'Web', 'Desktop', 'iOS',
'Android', 'UI/UX', 'Animation', 'Firebase', 'Provider', 'Riverpod'
];

@override
Widget build(BuildContext context) {
return Wrap(
spacing: 8.0,// 水平间距
runSpacing: 8.0,// 垂直间距
children: tags.map((tag) {
return Chip(
label: Text(tag),
avatar: CircleAvatar(
child: Text(tag[0]),
),
onDeleted: () {
setState(() {
tags.remove(tag);
});
},
);
}).toList(),
);
}
}

七、常见问题与解决方案

1. RenderFlex overflowed 错误

dart 复制代码
// ❌ 错误:Row中内容超出屏幕
Row(
children: [
Container(width: 400, color: Colors.red),
Container(width: 400, color: Colors.blue),
],
)

// ✅ 解决方案1:使用SingleChildScrollView包裹
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [/* 宽组件 */],
),
)

// ✅ 解决方案2:使用Expanded
Row(
children: [
Expanded(child: Container(color: Colors.red)),
Expanded(child: Container(color: Colors.blue)),
],
)

2. 嵌套弹性布局问题

dart 复制代码
// ❌ 错误:无限高度问题
Column(
children: [
Expanded(// Column内部使用Expanded
child: Container(color: Colors.red),
),
],
)

// ✅ 解决方案:确保父级有明确高度
Container(
height: 200,// 指定高度
child: Column(
children: [
Expanded(child: Container(color: Colors.red)),
],
),
)

3. Column/Row 内部滚动

dart 复制代码
// 使用Expanded包裹ListView/GridView
Column(
children: [
Container(height: 100, color: Colors.red),
Expanded(// 让ListView占用剩余空间
child: ListView.builder(
itemCount: 50,
itemBuilder: (context, index) => ListTile(title: Text('Item $index')),
),
),
],
)

八、最佳实践

  1. 选择合适的组件
  • 单行/单列布局:使用 Row/Column
  • 动态方向布局:使用 Flex
  • 需要填满空间:使用 Expanded
  • 灵活空间占用:使用 Flexible
  1. 性能优化
dart 复制代码
// 使用const减少重建
Column(
children: const [
SizedBox(height: 10),
Text('Title'),
Divider(),
],
)
  1. 响应式设计
dart 复制代码
LayoutBuilder(
builder: (context, constraints) {
return constraints.maxWidth > 600
? Row(children: [/* 水平布局 */])
: Column(children: [/* 垂直布局 */]);
},
)
  1. 组合使用
dart 复制代码
Column(
children: [
// 固定高度的Header
Container(height: 60, child: Header()),

// 可滚动的中间内容
Expanded(
child: ListView(
children: [/* 内容项 */],
),
),

// 固定高度的Footer
Container(height: 60, child: Footer()),
],
)

弹性布局是 Flutter 中最常用的布局方式,掌握好这些组件的使用,可以轻松构建各种复杂的界面布局。记住多实践,理解主轴和交叉轴的概念,这是掌握弹性布局的关键。

相关推荐
LawrenceLan2 小时前
38.Flutter 零基础入门(三十八):网络请求实战 http、dio —— 获取列表与刷新 UI
开发语言·前端·flutter·dart
im_AMBER2 小时前
Leetcode 136 最小栈 | 逆波兰表达式求值
数据结构·学习·算法·leetcode·
ITKEY_2 小时前
macOS flutter开发环境之cocoapods
flutter·macos·cocoapods
Xzq2105092 小时前
网络基础学习(一)
网络·学习
前端不太难2 小时前
Flutter / iOS 迁移鸿蒙 ArkUI 的真实成本
flutter·ios·harmonyos
Fuliy962 小时前
第三阶段:进化与群体智能 (Evolutionary & Swarm Intelligence)
人工智能·笔记·python·学习·算法
ejinxian2 小时前
Go语言完整学习规划(2026版)- Part 1
学习·go
小陈phd2 小时前
多模态大模型学习笔记(十六)——Transformer 学习之 Decoder Only
人工智能·笔记·深度学习·学习·自然语言处理·transformer
SuperEugene2 小时前
Excel 上传解析 + 导出实战:Vue+xlsx 避坑指南|Vue生态精选
前端·javascript·vue.js·excel·xlsx·vxetable