作者高红帆Math_teacher_fan仓库地址https://gitcode.com/feng8403000/FlutterfromBeginnertoAdvancedForHarmonyOS.git联系邮箱372699828qq.com引言在Flutter布局体系中Flex是一个强大的弹性布局组件它是Row和Column的父类提供了更灵活的布局能力。Flex结合Flexible和Spacer组件可以实现复杂的响应式布局。本文将深入探讨Flex布局的原理、Flexible组件的使用方法以及Spacer组件的应用场景。一、Flex布局基础1.1 Flex概念Flex是一个通用的弹性布局容器它可以在水平或垂直方向上排列子组件Flex(direction:Axis.horizontal,children:[Container(width:80,height:80,color:Colors.red),Container(width:80,height:80,color:Colors.green),Container(width:80,height:80,color:Colors.blue),],);1.2 Flex与Row/Column的关系组件方向说明Flex可配置通用弹性布局容器Row水平Flex(direction: Axis.horizontal)的特例Column垂直Flex(direction: Axis.vertical)的特例1.3 Flex构造函数Flex({Key?key,requiredthis.direction,this.mainAxisAlignmentMainAxisAlignment.start,this.mainAxisSizeMainAxisSize.max,this.crossAxisAlignmentCrossAxisAlignment.center,this.textDirection,this.verticalDirectionVerticalDirection.down,this.clipBehaviorClip.none,ListWidgetchildrenconstWidget[],})二、Flexible组件2.1 Flexible基础用法Flexible组件用于控制子组件在Flex布局中的弹性行为Flex(direction:Axis.horizontal,children:[Flexible(flex:1,child:Container(height:60,color:Colors.red),),Flexible(flex:2,child:Container(height:60,color:Colors.green),),Flexible(flex:1,child:Container(height:60,color:Colors.blue),),],);2.2 Flexible属性说明属性类型默认值说明flexint1弹性系数决定子组件占据剩余空间的比例fitFlexFitFlexFit.loose控制子组件如何填充分配的空间childWidget-子组件2.3 FlexFit两种模式enumFlexFit{loose,tight,}模式效果说明loose子组件只占据其内容所需空间Flexible默认模式tight子组件强制填满分配的空间Expanded使用此模式2.4 Flexible构造函数constFlexible({Key?key,this.flex1,this.fitFlexFit.loose,requiredWidgetchild,})三、Expanded组件3.1 Expanded与Flexible的关系Expanded是Flexible的一个特例它设置fit: FlexFit.tight// Expanded等价于Flexible(flex:1,fit:FlexFit.tight,child:...)// 源码定义classExpandedextendsFlexible{constExpanded({super.key,super.flex,requiredsuper.child,}):super(fit:FlexFit.tight);}3.2 Expanded基础用法Row(children:[Expanded(flex:2,child:Container(height:60,color:Colors.red),),Expanded(flex:1,child:Container(height:60,color:Colors.green),),],);3.3 Expanded与Flexible对比Row(children:[// Expanded - 强制填满分配空间Expanded(flex:1,child:Container(height:60,color:Colors.red),),// Flexible - 只占据内容所需空间Flexible(flex:1,fit:FlexFit.loose,child:Container(height:60,color:Colors.green),),],);四、Spacer组件4.1 Spacer基础用法Spacer组件用于在子组件之间创建弹性空间Row(children:[Container(width:60,height:60,color:Colors.red),constSpacer(),Container(width:60,height:60,color:Colors.green),constSpacer(flex:2),Container(width:60,height:60,color:Colors.blue),],);4.2 Spacer属性说明属性类型默认值说明flexint1空间弹性系数4.3 Spacer与Flexible对比// Spacer等价于Flexible(flex:1,fit:FlexFit.tight,child:constSizedBox.shrink())// 源码定义classSpacerextendsStatelessWidget{constSpacer({super.key,this.flex1});// ...}4.4 Spacer使用场景// 场景1两端对齐Row(children:[constText(左侧),constSpacer(),constText(右侧),],);// 场景2三等分间距Row(children:[Container(width:50,height:50,color:Colors.red),constSpacer(flex:1),Container(width:50,height:50,color:Colors.green),constSpacer(flex:1),Container(width:50,height:50,color:Colors.blue),],);五、flex属性详解5.1 flex系数计算flex属性决定了子组件在剩余空间中的分配比例// 假设剩余空间为400像素// flex比例为1:2:1// 总比例 1 2 1 4// 红色 400 * 1/4 100像素// 绿色 400 * 2/4 200像素// 蓝色 400 * 1/4 100像素Row(children:[Expanded(flex:1,child:Container(height:60,color:Colors.red)),Expanded(flex:2,child:Container(height:60,color:Colors.green)),Expanded(flex:1,child:Container(height:60,color:Colors.blue)),],);5.2 flex为0的情况当flex为0时子组件不参与弹性分配Row(children:[Expanded(flex:1,child:Container(height:60,color:Colors.red)),// flex为0不参与弹性分配Flexible(flex:0,child:Container(width:100,height:60,color:Colors.green)),Expanded(flex:1,child:Container(height:60,color:Colors.blue)),],);5.3 混合使用固定尺寸和弹性布局Row(children:[// 固定尺寸Container(width:80,height:60,color:Colors.red),// 弹性分配剩余空间Expanded(child:Container(height:60,color:Colors.green)),// 固定尺寸Container(width:80,height:60,color:Colors.blue),],);六、Flex布局实战6.1 响应式布局Flex(direction:MediaQuery.of(context).size.width600?Axis.horizontal:Axis.vertical,children:[Expanded(child:Container(height:200,color:Colors.red)),Expanded(child:Container(height:200,color:Colors.green)),],);6.2 复杂表单布局Column(children:[Row(children:[Expanded(flex:1,child:TextFormField(decoration:constInputDecoration(labelText:姓)),),constSizedBox(width:10),Expanded(flex:2,child:TextFormField(decoration:constInputDecoration(labelText:名)),),],),constSizedBox(height:20),Expanded(child:TextFormField(maxLines:3,decoration:constInputDecoration(labelText:详细地址),),),],);6.3 底部操作栏Row(children:[ElevatedButton(onPressed:(){},child:constText(取消),),constSpacer(),ElevatedButton(onPressed:(){},style:ElevatedButton.styleFrom(backgroundColor:Colors.blue),child:constText(确认),),],);6.4 卡片布局Card(child:Padding(padding:constEdgeInsets.all(16),child:Column(children:[Row(children:[constCircleAvatar(radius:20),constSizedBox(width:12),Expanded(child:Column(crossAxisAlignment:CrossAxisAlignment.start,children:const[Text(用户名,style:TextStyle(fontWeight:FontWeight.bold)),Text(用户描述),],),),constIcon(Icons.more_vert),],),constSizedBox(height:16),Expanded(child:Container(color:Colors.grey[200]),),constSizedBox(height:16),Row(children:[constIcon(Icons.favorite_border),constSizedBox(width:8),constText(点赞),constSpacer(),constIcon(Icons.comment),constSizedBox(width:8),constText(评论),constSpacer(),constIcon(Icons.share),constSizedBox(width:8),constText(分享),],),],),),);七、Flex布局常见问题7.1 问题1Flex子组件溢出问题描述Flex中的子组件总尺寸超过容器尺寸。解决方案使用Expanded或Flexible// 错误Flex(direction:Axis.horizontal,children:[Container(width:400,height:60,color:Colors.red),Container(width:400,height:60,color:Colors.green),],);// 正确Flex(direction:Axis.horizontal,children:[Expanded(child:Container(height:60,color:Colors.red)),Expanded(child:Container(height:60,color:Colors.green)),],);7.2 问题2Flexible子组件不收缩问题描述Flexible设置为loose模式时子组件不收缩。解决方案使用tight模式或Expanded// 不收缩Flexible(fit:FlexFit.loose,child:Container(width:400,height:60,color:Colors.red),),// 收缩Flexible(fit:FlexFit.tight,child:Container(height:60,color:Colors.red),),7.3 问题3Spacer不生效问题描述Spacer在某些情况下不创建空间。解决方案确保父容器有足够的空间// 错误 - Container没有宽度约束Container(child:Row(children:[constText(左侧),constSpacer(),constText(右侧),],),);// 正确 - 添加宽度约束Container(width:double.infinity,child:Row(children:[constText(左侧),constSpacer(),constText(右侧),],),);7.4 问题4嵌套Flex布局问题描述在Column中嵌套Row内部Row的Expanded不生效。解决方案确保Column有确定的高度Column(children:[// 错误 - Row没有高度约束Row(children:[Expanded(child:Container(color:Colors.red)),Expanded(child:Container(color:Colors.green)),],),// 正确 - 使用Expanded包裹RowExpanded(child:Row(children:[Expanded(child:Container(color:Colors.red)),Expanded(child:Container(color:Colors.green)),],),),],);八、Flex布局性能优化8.1 避免不必要的嵌套// 不推荐 - 多余的嵌套Row(children:[Flexible(child:Container(child:Row(children:[...])),),],);// 推荐 - 直接使用Row(children:[...],);8.2 使用const构造函数// 推荐constSpacer(flex:1);constSizedBox(width:10);8.3 合理使用flex系数// 避免过大的flex值Expanded(flex:1000,child:...);// 使用合理的值Expanded(flex:1,child:...);Expanded(flex:2,child:...);九、Flex布局与其他布局对比9.1 Flex vs GridView布局适用场景特点Flex线性排列一维布局灵活控制比例GridView网格排列二维布局固定行列数9.2 Flex vs Stack布局适用场景特点Flex线性排列子组件按顺序排列Stack层叠排列子组件重叠显示9.3 Flex vs Wrap布局适用场景特点Flex单行/单列不自动换行Wrap多行/多列自动换行十、Flex布局最佳实践10.1 何时使用Flex需要精确控制子组件比例时需要响应式布局时需要复杂的弹性空间分配时10.2 何时使用Flexible子组件不需要填满空间时子组件尺寸可变时需要保持子组件原始尺寸时10.3 何时使用Expanded子组件需要填满空间时子组件尺寸固定时需要强制拉伸时10.4 何时使用Spacer需要在子组件间创建弹性空间时需要两端对齐时需要等分间距时十一、总结通过本文的学习我们掌握了以下核心知识点Flex是通用弹性布局容器Row和Column是其特例Flexible控制子组件的弹性行为通过flex和fit属性配置Expanded是Flexible(fit: FlexFit.tight)的快捷方式强制填满空间Spacer用于创建弹性空间等价于Flexible(flex: 1, fit: FlexFit.tight, child: SizedBox.shrink())flex系数决定子组件在剩余空间中的分配比例掌握Flex布局的使用方法对于构建响应式和复杂的Flutter界面至关重要。合理组合Flexible、Expanded和Spacer组件可以实现各种灵活的布局效果。参考资料Flutter官方文档https://docs.flutter.dev/Flex Widgethttps://api.flutter.dev/flutter/widgets/Flex-class.htmlFlexible Widgethttps://api.flutter.dev/flutter/widgets/Flexible-class.htmlExpanded Widgethttps://api.flutter.dev/flutter/widgets/Expanded-class.htmlSpacer Widgethttps://api.flutter.dev/flutter/widgets/Spacer-class.html