☰
【Flutter入门练中学】第2课:布局系统
2026/10/9 2:37:30 网站建设 项目流程

目标

· 理解 Flutter 布局核心口诀:父传约束,子定尺寸,父定位置。
· 分清 Row / Column 的主轴与交叉轴,掌握 mainAxisAlignment 和 crossAxisAlignment。
· 掌握 Container、Padding、SizedBox、Expanded、Spacer 的用途。
· 能组合实现个人信息行、上中下布局、商品卡片、音乐播放器。
· 能识别并修复 RenderFlex overflowed 溢出错误。
· 通过“题目要求 → 答案 → 答案解读”的多元化习题完成练中学。


一、本课核心概念速览

Flutter 布局口诀:

父传约束,子定尺寸,父定位置。

常用布局 Widget:

Widget 作用
Row 水平排列
Column 垂直排列
Container 盒子:尺寸、颜色、边距、圆角、对齐
Padding 内边距
Margin 外边距,通常用 Container 的 margin
Expanded 按比例占满剩余空间
Flexible 灵活占空间,可松可紧
Spacer 占剩余空间,做间隔
SizedBox 固定宽高或间距
Align / Center 对齐 / 居中
MainAxisAlignment 主轴对齐
CrossAxisAlignment 交叉轴对齐

Row 的主轴是水平,交叉轴是垂直。
Column 的主轴是垂直,交叉轴是水平。


二、最小可运行示例

把 lib/main.dart 改成:

import'package:flutter/material.dart';voidmain(){runApp(constMyApp());}classMyAppextendsStatelessWidget{constMyApp({super.key});@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(home:Scaffold(body:Center(child:Row(mainAxisAlignment:MainAxisAlignment.spaceEvenly,children:const[Text('左'),Text('中'),Text('右'),],),),),);}}

按 r 热重载,把 spaceEvenly 改成 spaceBetween、center、end,观察变化。


三、多元化习题

练习0:热重载体验布局

题目要求
运行上面的 Row 示例,依次把 mainAxisAlignment 改成:

· MainAxisAlignment.start
· MainAxisAlignment.center
· MainAxisAlignment.end
· MainAxisAlignment.spaceBetween
· MainAxisAlignment.spaceAround
· MainAxisAlignment.spaceEvenly

记录每个值的效果。

答案

Row(mainAxisAlignment:MainAxisAlignment.spaceBetween,children:const[Text('左'),Text('中'),Text('右'),],)

各值效果:

· start:靠左。
· center:整体居中。
· end:靠右。
· spaceBetween:两端贴边,中间等距。
· spaceAround:每个子项两侧等距。
· spaceEvenly:所有间隔完全相等,包括两端。

答案解读
mainAxisAlignment 控制主轴方向的对齐。Row 的主轴是水平,所以这些值控制水平分布。Column 的主轴是垂直,同样的值会控制垂直分布。热重载可以立刻看到差异,是练布局最快的方式。


练习1:选择题

题目要求
在 Column 中,crossAxisAlignment 控制的是哪个方向?

A. 垂直方向
B. 水平方向
C. 文字颜色
D. 内外边距

答案
B。

答案解读
Column 的主轴是垂直,交叉轴是水平。所以 mainAxisAlignment 控制垂直对齐,crossAxisAlignment 控制水平对齐。Row 刚好相反。


练习2:判断题

题目要求
判断对错,并说明理由:

  1. Expanded 必须直接放在 Row、Column 或 Flex 的子级中。
  2. Container 的 padding 是外边距,margin 是内边距。
  3. Spacer 可以用在 Row 和 Column 中。
  4. SizedBox 只能用来显示文字。

答案

  1. 对。
  2. 错。
  3. 对。
  4. 错。

答案解读
Expanded 依赖 Flex 父级分配剩余空间,所以不能随便放在普通 Container 里。padding 是内边距,margin 是外边距。Spacer 本质是 Expanded(child: SizedBox()),可用在 Row/Column。SizedBox 是尺寸盒子,常用于占位和间距,不显示文字。


练习3:连线题

题目要求
将左侧 Widget 与右侧作用连线:

左侧 右侧
mainAxisAlignment 交叉轴对齐
crossAxisAlignment 主轴对齐
Expanded 固定尺寸或间距
Spacer 按比例占剩余空间
SizedBox 占剩余空间形成间隔
Padding 内边距

答案

· mainAxisAlignment — 主轴对齐
· crossAxisAlignment — 交叉轴对齐
· Expanded — 按比例占剩余空间
· Spacer — 占剩余空间形成间隔
· SizedBox — 固定尺寸或间距
· Padding — 内边距

答案解读
这些是布局系统最常用的成员。先分清主轴和交叉轴,再理解剩余空间怎么分配,布局就不容易乱。


练习4:排序题

题目要求
实现“页面居中显示一个圆角盒子,盒子里有内边距,文字居中”。按从外到内的嵌套顺序排列:

Text、Center、Container、Padding

答案
Center → Container → Padding → Text

答案解读
Center 负责整体居中,Container 负责尺寸、颜色、圆角,Padding 负责文字与盒子边缘的距离,Text 是最内层内容。实际开发中,Container 自带 padding,也可以省掉单独的 Padding。


练习5:填空题

题目要求
补全代码,让三个文字“左、中、右”分别贴在两端和中间:

Row(mainAxisAlignment:______,children:const[Text('左'),Text('中'),Text('右'),],)

答案

Row(mainAxisAlignment:MainAxisAlignment.spaceBetween,children:const[Text('左'),Text('中'),Text('右'),],)

答案解读
spaceBetween 会把第一个和最后一个推到两端,中间的子项等距分布。做顶部栏、底部栏、左右分布时非常常用。


练习6:代码预测题

题目要求
阅读代码,预测屏幕显示效果:

body:Center(child:Column(mainAxisAlignment:MainAxisAlignment.center,children:const[Text('上'),SizedBox(height:20),Text('下'),],),)

答案
“上”和“下”垂直排列,整体在屏幕中间,两者之间有 20 像素间距。

答案解读
Center 让 Column 在页面居中。Column 的 mainAxisAlignment.center 让子项在垂直方向整体居中。SizedBox(height: 20) 提供固定垂直间距。


练习7:改错题

题目要求
下面代码会导致布局溢出,找出来并修正:

Row(children:const[Text('这是一段非常非常长的文字,可能会撑爆屏幕'),Text('这也是一段非常非常长的文字,也可能撑爆屏幕'),],)

答案
修正方式之一:

Row(children:const[Expanded(child:Text('这是一段非常非常长的文字,可能会撑爆屏幕',overflow:TextOverflow.ellipsis,),),Expanded(child:Text('这也是一段非常非常长的文字,也可能撑爆屏幕',overflow:TextOverflow.ellipsis,),),],)

答案解读
Row 主轴方向给子项无限宽度约束,长文字会按自身宽度撑开,超出屏幕就报 RenderFlex overflowed。用 Expanded 让文字按剩余空间分配宽度,再用 overflow: TextOverflow.ellipsis 显示省略号。这是实际开发中最常见的布局修复之一。


练习8:补全代码题

题目要求
补全代码,做一个 120×60 的蓝色圆角盒子,内部有 12 内边距,外边距 8,文字白色居中:

Container(width:120,height:60,padding:constEdgeInsets.all(______),margin:constEdgeInsets.all(______),decoration:BoxDecoration(color:Colors.blue,borderRadius:BorderRadius.circular(______),),alignment:Alignment.______,child:constText('按钮',style:TextStyle(color:Colors.white),),)

答案

Container(width:120,height:60,padding:constEdgeInsets.all(12),margin:constEdgeInsets.all(8),decoration:BoxDecoration(color:Colors.blue,borderRadius:BorderRadius.circular(12),),alignment:Alignment.center,child:constText('按钮',style:TextStyle(color:Colors.white),),)

答案解读
padding 是盒子内部留白,margin 是盒子外部留白。BoxDecoration 用来设置背景色和圆角。alignment: Alignment.center 让 child 在盒子内居中。注意:使用 decoration 时,颜色要写在 BoxDecoration 里,不能同时写 color。


练习9:动手编码题:个人信息行

题目要求
用 Row 做一行个人信息:左边一个圆形头像,中间显示姓名和职业,右边一个按钮。要求中间区域用 Expanded 包裹,防止文字太长溢出。

答案

body:Center(child:Padding(padding:constEdgeInsets.all(16),child:Row(children:[Container(width:56,height:56,decoration:constBoxDecoration(color:Colors.blue,shape:BoxShape.circle,),alignment:Alignment.center,child:constText('张',style:TextStyle(color:Colors.white,fontSize:20),),),constSizedBox(width:12),constExpanded(child:Column(crossAxisAlignment:CrossAxisAlignment.start,mainAxisSize:MainAxisSize.min,children:[Text('张三',style:TextStyle(fontSize:18,fontWeight:FontWeight.bold),),SizedBox(height:4),Text('Flutter 开发者'),],),),constSizedBox(width:12),ElevatedButton(onPressed:(){},child:constText('关注'),),],),),)

答案解读
Row 水平排列头像、信息、按钮。中间用 Expanded 占剩余宽度,避免长文字溢出。Column 的 crossAxisAlignment.start 让姓名和职业左对齐。mainAxisSize: MainAxisSize.min 让 Column 高度尽量小。圆形头像用 BoxShape.circle。


练习10:动手编码题:上中下布局

题目要求
用 Column 和 Expanded 做上中下布局:顶部固定高度 60,中间占满剩余空间,底部固定高度 60。三个区域用不同颜色区分。

答案

body:Column(children:[Container(height:60,color:Colors.blue,alignment:Alignment.center,child:constText('顶部',style:TextStyle(color:Colors.white)),),Expanded(child:Container(color:Colors.grey.shade200,alignment:Alignment.center,child:constText('中间占满剩余空间'),),),Container(height:60,color:Colors.green,alignment:Alignment.center,child:constText('底部',style:TextStyle(color:Colors.white)),),],)

答案解读
Column 垂直排列。顶部和底部用固定高度,中间用 Expanded 吃掉剩余高度。这是 App 页面最经典的骨架:顶部栏 + 内容区 + 底部栏。


练习11:综合挑战:商品卡片

题目要求
做一个商品卡片:外层圆角阴影,内部有内边距。左边一个商品图标,中间显示商品名和描述,右边显示价格和购买按钮。要求使用 Container、Padding、Row、Column、Expanded、SizedBox。

答案

body:Center(child:Container(margin:constEdgeInsets.all(16),padding:constEdgeInsets.all(16),decoration:BoxDecoration(color:Colors.white,borderRadius:BorderRadius.circular(16),boxShadow:[BoxShadow(color:Colors.black.withOpacity(0.1),blurRadius:8,offset:constOffset(0,4),),],),child:Row(children:[Container(width:64,height:64,decoration:BoxDecoration(color:Colors.orange.shade100,borderRadius:BorderRadius.circular(12),),alignment:Alignment.center,child:constIcon(Icons.shopping_bag,color:Colors.orange,size:32),),constSizedBox(width:12),constExpanded(child:Column(crossAxisAlignment:CrossAxisAlignment.start,mainAxisSize:MainAxisSize.min,children:[Text('Flutter 实战课',style:TextStyle(fontSize:18,fontWeight:FontWeight.bold),),SizedBox(height:6),Text('从零开始,练中学布局系统',style:TextStyle(color:Colors.grey),),],),),constSizedBox(width:12),Column(mainAxisSize:MainAxisSize.min,children:[constText('¥99',style:TextStyle(fontSize:18,color:Colors.red,fontWeight:FontWeight.bold,),),constSizedBox(height:8),ElevatedButton(onPressed:(){},child:constText('购买'),),],),],),),)

答案解读
外层 Container 负责卡片边距、圆角、阴影。内部 Row 分三列:图标、信息、价格按钮。中间信息列用 Expanded 占剩余宽度。右侧价格按钮用 Column 垂直排列。这个练习把本课大部分布局知识综合了起来。


练习12:开放式挑战:音乐播放器界面

题目要求
用 Column、Expanded、Row、Container、Icon 设计一个简单的音乐播放器界面。要求:

· 顶部显示歌曲名;
· 中间 Expanded 区域显示专辑封面占位;
· 底部一排控制按钮:上一首、播放、下一首。

答案示例

body:SafeArea(child:Column(children:[constPadding(padding:EdgeInsets.all(16),child:Text('正在播放:练中学',style:TextStyle(fontSize:20,fontWeight:FontWeight.bold),),),Expanded(child:Container(margin:constEdgeInsets.all(24),decoration:BoxDecoration(color:Colors.deepPurple.shade100,borderRadius:BorderRadius.circular(24),),alignment:Alignment.center,child:constIcon(Icons.music_note,size:80,color:Colors.deepPurple,),),),Padding(padding:constEdgeInsets.all(16),child:Row(mainAxisAlignment:MainAxisAlignment.spaceEvenly,children:[IconButton(onPressed:(){},icon:constIcon(Icons.skip_previous,size:36),),IconButton(onPressed:(){},icon:constIcon(Icons.play_circle_fill,size:64),),IconButton(onPressed:(){},icon:constIcon(Icons.skip_next,size:36),),],),),],),)

答案解读
整体用 Column:顶部标题、中间 Expanded 封面、底部控制栏。中间 Expanded 占满剩余空间。底部 Row 用 spaceEvenly 均匀排列按钮。开放题没有唯一答案,重点是布局结构清晰、能运行、能热重载修改。


练习13:错误观察挑战

题目要求
故意制造一次 RenderFlex overflowed 错误:在 Row 中放两个很长的 Text,不要用 Expanded。运行后观察控制台错误,记录关键错误词。

答案
示例错误代码:

Row(children:const[Text('这是一段非常非常非常非常非常非常非常长的文字'),Text('这也是一段非常非常非常非常非常非常非常长的文字'),],)

控制台常见错误:

A RenderFlex overflowed by 123 pixels on the right.

答案解读
RenderFlex 是 Row/Column 的渲染对象。当子项总宽度超过可用宽度时,就会溢出。右侧溢出会提示 on the right,Column 溢出会提示 on the bottom。解决方法:用 Expanded、Flexible、SingleChildScrollView 或 TextOverflow.ellipsis。学会看这个错误,布局能力会提升很快。


四、本课小结

这一课你练了:

  1. Row 和 Column 的主轴、交叉轴;
  2. mainAxisAlignment 和 crossAxisAlignment;
  3. Container、Padding、Margin、SizedBox;
  4. Expanded、Spacer 分配剩余空间;
  5. 用 Row/Column 组合出个人信息行、上中下布局、商品卡片、音乐播放器;
  6. 通过故意制造溢出,学会看 RenderFlex overflowed 错误。

下一课可以进入 滚动与列表:ListView、SingleChildScrollView、GridView,继续用“练中学”的方式做可滚动页面。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询