一、Widget 核心概念
1.1 Widget 是什么
在 Flutter 中,一切皆 Widget。Widget 是 Flutter UI 的最小构建单元,描述了界面的某一部分"应该长什么样"。
需要特别注意的是:Widget 本身是不可变的配置描述,而非真实渲染的 UI 元素。每当状态发生变化,Flutter 不会修改原有 Widget,而是重新创建新的 Widget 树,由框架负责高效地做差异化更新。
dart
// Widget 是 UI 配置的声明
Text('Hello Flutter')
// 等价于一个描述"显示文字 Hello Flutter"的数据结构
这种设计带来了几个优势:
- 不可变性保证了线程安全
- 重建代价极低(Widget 是轻量级对象)
- 声明式 UI 让代码更加可预测
1.2 StatelessWidget vs StatefulWidget
StatelessWidget --- 无状态组件
适合纯展示型 UI,内部没有可变数据。一旦构建完成,显示内容不会改变(除非父级传入新的参数)。
dart
class MyLabel extends StatelessWidget {
final String text;
const MyLabel({super.key, required this.text});
@override
Widget build(BuildContext context) {
return Text(
text,
style: const TextStyle(fontSize: 16),
);
}
}
生命周期 :父节点 build → build() → 渲染。没有额外生命周期回调。
StatefulWidget --- 有状态组件
当 Widget 需要持有随时间变化的数据时,使用 StatefulWidget。它由两个类共同组成:
dart
// Widget 类:仍然是不可变的
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
// State 类:持有可变状态
class _CounterState extends State<Counter> {
int _count = 0;
void _increment() {
setState(() { // 告知框架状态已变化,触发重建
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_count'),
ElevatedButton(
onPressed: _increment,
child: const Text('加一'),
),
],
);
}
}
State 生命周期(重要!):
initState() ← 初始化,仅调用一次
↓
didChangeDependencies() ← 依赖(如 InheritedWidget)变化时调用
↓
build() ← 每次 setState / 父重建都会调用
↓
didUpdateWidget() ← 父传入新 widget 实例时调用
↓
deactivate() ← 从树中移除时
↓
dispose() ← 彻底销毁,释放资源(Controller、Timer 等)
选择原则:
| 场景 | 选择 |
|---|---|
| 纯展示、无交互 | StatelessWidget |
| 有用户输入、动画、网络数据 | StatefulWidget |
| 多组件共享状态 | Provider / Riverpod / Bloc |
1.3 Widget 树 / Element 树 / RenderObject 树
Flutter 运行时维护三棵并行的树,理解它们是深入 Flutter 的关键。
Widget 树(配置层)
↕ 映射
Element 树(生命周期管理层)
↕ 映射
RenderObject 树(布局与绘制层)
Widget 树
开发者直接书写的部分。轻量、可频繁重建。描述"想要什么"。
Element 树
Flutter 框架自动维护。每个 Widget 对应一个 Element,Element 持有对 Widget 和 RenderObject 的引用。负责管理生命周期,并做新旧 Widget 的 diff(通过 key 和 runtimeType 判断是否复用)。
RenderObject 树
真正执行布局(layout)和绘制(paint)的对象。代价较高,Flutter 会尽量复用。
Column Widget → ColumnElement → RenderFlex
Text Widget → TextElement → RenderParagraph
Icon Widget → IconElement → RenderBox
实际意义 :当你调用 setState(),Flutter 重建 Widget 树,然后通过 Element 树进行 diff,只对真正变化的部分更新 RenderObject。这就是 Flutter 高性能的核心所在。
1.4 BuildContext 理解
BuildContext 是 Element 在 Widget 树中位置的句柄。每个 build(BuildContext context) 中的 context 代表当前 Widget 在树中的位置。
dart
@override
Widget build(BuildContext context) {
// 通过 context 向上查找最近的 Theme
final theme = Theme.of(context);
// 通过 context 获取屏幕尺寸
final size = MediaQuery.of(context).size;
// 通过 context 进行路由跳转
Navigator.of(context).push(...);
return Container(color: theme.primaryColor);
}
常见误区 :不要在 initState() 里直接使用 context(此时 Widget 还未挂载完成),应使用 didChangeDependencies() 或者用 WidgetsBinding.instance.addPostFrameCallback 延迟执行。
二、基础 UI 组件
2.1 文本:Text / RichText
Text
最常用的文本组件,支持单一样式。
dart
Text(
'欢迎使用 Flutter',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.deepPurple,
letterSpacing: 1.2,
height: 1.5, // 行高倍数
),
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis, // 超出截断并显示省略号
)
RichText
当同一段文字需要多种样式时,使用 RichText + TextSpan。
dart
RichText(
text: TextSpan(
style: const TextStyle(fontSize: 16, color: Colors.black),
children: [
const TextSpan(text: '价格:'),
TextSpan(
text: '¥99.00',
style: const TextStyle(
color: Colors.red,
fontWeight: FontWeight.bold,
fontSize: 20,
),
),
const TextSpan(text: ' 起'),
],
),
)
实用技巧 :
Text.rich()是RichText的便捷构造器,自动继承DefaultTextStyle,推荐在一般场景使用。
2.2 图片:Image / AssetImage / NetworkImage
dart
// 加载网络图片
Image.network(
'https://example.com/photo.jpg',
width: 200,
height: 150,
fit: BoxFit.cover, // 裁剪填满
loadingBuilder: (context, child, progress) {
if (progress == null) return child;
return const CircularProgressIndicator();
},
errorBuilder: (context, error, stackTrace) {
return const Icon(Icons.broken_image);
},
)
// 加载本地资源图片(需在 pubspec.yaml 中声明)
Image.asset(
'assets/images/logo.png',
width: 100,
)
// 圆形头像(配合 ClipOval)
ClipOval(
child: Image.network(
'https://example.com/avatar.jpg',
width: 60,
height: 60,
fit: BoxFit.cover,
),
)
BoxFit 速查:
| 值 | 效果 |
|---|---|
cover |
等比缩放,铺满容器,可能裁剪 |
contain |
等比缩放,完整显示,可能留白 |
fill |
拉伸填满,不保持比例 |
fitWidth |
宽度填满,高度等比 |
fitHeight |
高度填满,宽度等比 |
none |
原始尺寸,超出裁剪 |
2.3 按钮组件
ElevatedButton --- 凸起按钮(主操作)
dart
ElevatedButton(
onPressed: () => print('点击了'),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.deepPurple,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text('立即购买'),
)
TextButton --- 文字按钮(次级操作)
dart
TextButton(
onPressed: () {},
child: const Text('查看详情'),
)
IconButton --- 图标按钮
dart
IconButton(
icon: const Icon(Icons.favorite_border),
onPressed: () {},
tooltip: '收藏',
iconSize: 28,
color: Colors.pink,
)
GestureDetector --- 手势识别器(万能)
当系统按钮满足不了需求时,用 GestureDetector 给任意 Widget 添加手势。
dart
GestureDetector(
onTap: () => print('单击'),
onDoubleTap: () => print('双击'),
onLongPress: () => print('长按'),
onPanUpdate: (details) {
// 拖动,details.delta 是偏移量
},
child: Container(
width: 100,
height: 100,
color: Colors.blue,
child: const Center(child: Text('点我')),
),
)
InkWell vs GestureDetector :
InkWell带有 Material 水波纹效果,适合 Material 风格 UI;GestureDetector无任何视觉反馈,适合自定义 UI。
2.4 输入框:TextField / TextFormField
TextField --- 基础输入框
dart
final _controller = TextEditingController();
TextField(
controller: _controller,
decoration: InputDecoration(
labelText: '用户名',
hintText: '请输入用户名',
prefixIcon: const Icon(Icons.person),
suffixIcon: IconButton(
icon: const Icon(Icons.clear),
onPressed: () => _controller.clear(),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
keyboardType: TextInputType.emailAddress,
obscureText: false, // 密码输入时设为 true
maxLength: 20,
onChanged: (value) => print(value),
onSubmitted: (value) => print('提交:$value'),
)
TextFormField --- 表单输入框(带验证)
dart
final _formKey = GlobalKey<FormState>();
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: const InputDecoration(labelText: '邮箱'),
validator: (value) {
if (value == null || value.isEmpty) return '邮箱不能为空';
if (!value.contains('@')) return '请输入有效邮箱';
return null; // null 表示验证通过
},
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// 验证通过,提交表单
}
},
child: const Text('提交'),
),
],
),
)
FocusNode 管理焦点:
dart
final _focusNode = FocusNode();
// 主动获取焦点
_focusNode.requestFocus();
// 失去焦点(收起键盘)
_focusNode.unfocus();
// 记得在 dispose 中释放
@override
void dispose() {
_focusNode.dispose();
_controller.dispose();
super.dispose();
}
2.5 图标:Icon
dart
// 使用 Material Icons
Icon(
Icons.star,
size: 32,
color: Colors.amber,
)
// 带语义的图标(无障碍)
Icon(
Icons.favorite,
semanticLabel: '收藏',
)
// 自定义图标字体
Icon(
IconData(0xe001, fontFamily: 'MyIcons'),
)
三、布局 Widget
布局是 Flutter 开发最核心的技能之一。Flutter 的布局协议是父节点向子节点传递约束(constraints),子节点在约束范围内决定自身尺寸。
3.1 线性布局:Row / Column
dart
// Row:水平排列
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // 主轴对齐(水平)
crossAxisAlignment: CrossAxisAlignment.center, // 交叉轴对齐(垂直)
children: [
const Icon(Icons.star),
const Text('评分'),
const Text('4.8'),
],
)
// Column:垂直排列
Column(
mainAxisSize: MainAxisSize.min, // 收紧高度,不占满父容器
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('标题', style: TextStyle(fontSize: 18)),
const SizedBox(height: 8),
const Text('副标题'),
],
)
对齐方式速查:
| MainAxisAlignment | 效果 |
|---|---|
start |
靠起始端 |
end |
靠结束端 |
center |
居中 |
spaceBetween |
两端对齐,间隔均匀 |
spaceAround |
每个元素两侧间隔相等 |
spaceEvenly |
所有间隔相等(含两端) |
3.2 层叠布局:Stack / Positioned
Stack 允许子 Widget 堆叠在一起,后面的子 Widget 会覆盖前面的。
dart
Stack(
alignment: Alignment.center, // 未定位子 Widget 的默认对齐
children: [
// 背景图
Image.network('https://example.com/bg.jpg', fit: BoxFit.cover),
// 半透明遮罩
Container(color: Colors.black.withOpacity(0.3)),
// 定位的文字
Positioned(
bottom: 16,
left: 16,
right: 16,
child: const Text(
'封面标题',
style: TextStyle(color: Colors.white, fontSize: 24),
),
),
// 右上角角标
Positioned(
top: 8,
right: 8,
child: Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(4),
),
child: const Text('HOT', style: TextStyle(color: Colors.white, fontSize: 10)),
),
),
],
)
3.3 弹性布局:Expanded / Flexible
在 Row / Column 中,用 Expanded 和 Flexible 按比例分配剩余空间。
dart
Row(
children: [
// 固定宽度
const Icon(Icons.label, size: 20),
const SizedBox(width: 8),
// 占据剩余所有空间
Expanded(
child: Text('这是一段可能很长的标题文字,会自动换行'),
),
// 按 flex 比例分配
Flexible(
flex: 1,
child: Container(color: Colors.blue, height: 40),
),
Flexible(
flex: 2, // 占剩余空间的 2/3
child: Container(color: Colors.green, height: 40),
),
],
)
Expanded vs Flexible:
Expanded=Flexible(fit: FlexFit.tight),强制填满分配的空间Flexible默认fit: FlexFit.loose,子 Widget 可以比分配空间小
3.4 容器类 Widget
Container --- 万能容器
dart
Container(
width: 200,
height: 100,
margin: const EdgeInsets.all(16), // 外边距
padding: const EdgeInsets.symmetric( // 内边距
horizontal: 16, vertical: 8,
),
alignment: Alignment.center, // 子 Widget 对齐方式
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
offset: const Offset(0, 2),
),
],
),
child: const Text('卡片内容'),
)
注意 :
Container同时设置color和decoration会报错,两者选其一。颜色设置在decoration里。
SizedBox --- 尺寸盒子
dart
// 固定尺寸
SizedBox(width: 100, height: 50, child: myWidget)
// 常用于间距
const SizedBox(height: 16) // 垂直间距
const SizedBox(width: 8) // 水平间距
// 强制填满父容器
SizedBox.expand(child: myWidget)
Padding / Center / Align
dart
// 单纯添加内边距(比 Container 轻量)
Padding(
padding: const EdgeInsets.all(16),
child: myWidget,
)
// 居中
Center(child: myWidget)
// 自定义对齐
Align(
alignment: Alignment.bottomRight,
child: myWidget,
)
3.5 滚动组件
SingleChildScrollView --- 单子滚动
适合内容偶尔超出屏幕的页面,如表单页。
dart
SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
// 表单字段...
],
),
)
ListView --- 列表
dart
// 方式一:直接传 children(适合少量固定条目)
ListView(
children: [
ListTile(title: const Text('Item 1')),
ListTile(title: const Text('Item 2')),
],
)
// 方式二:builder(适合大量数据,懒加载)
ListView.builder(
itemCount: 100,
itemExtent: 60, // 固定行高,性能更好
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(child: Text('$index')),
title: Text('Item $index'),
subtitle: const Text('副标题'),
trailing: const Icon(Icons.chevron_right),
onTap: () {},
);
},
)
// 方式三:separated(自带分割线)
ListView.separated(
itemCount: items.length,
separatorBuilder: (context, index) => const Divider(height: 1),
itemBuilder: (context, index) => ListTile(title: Text(items[index])),
)
GridView --- 网格
dart
// 固定列数
GridView.count(
crossAxisCount: 2, // 列数
mainAxisSpacing: 12, // 纵向间距
crossAxisSpacing: 12, // 横向间距
childAspectRatio: 1.2, // 宽高比
padding: const EdgeInsets.all(16),
children: List.generate(20, (i) => Card(child: Center(child: Text('$i')))),
)
// 自适应列数(响应式)
GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 160, // 每列最大宽度
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 0.8,
),
itemCount: products.length,
itemBuilder: (context, index) => ProductCard(product: products[index]),
)
四、装饰与样式
4.1 BoxDecoration --- 盒子装饰
BoxDecoration 是 Container 的 decoration 属性,提供丰富的视觉效果。
dart
Container(
decoration: BoxDecoration(
// 背景色
color: Colors.white,
// 或渐变背景(与 color 互斥)
gradient: const LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [Color(0xFF6750A4), Color(0xFF03DAC6)],
),
// 圆角
borderRadius: BorderRadius.circular(16),
// 也可单独设置某个角
// borderRadius: BorderRadius.only(topLeft: Radius.circular(16)),
// 边框
border: Border.all(
color: Colors.purple.withOpacity(0.3),
width: 1.5,
),
// 阴影(可设多个)
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 16,
spreadRadius: 0,
offset: const Offset(0, 4),
),
],
// 背景图片
image: const DecorationImage(
image: NetworkImage('https://example.com/bg.jpg'),
fit: BoxFit.cover,
),
),
)
实用渐变类型:
dart
// 线性渐变
LinearGradient(
colors: [Colors.blue, Colors.purple],
stops: [0.0, 1.0], // 可选:指定颜色断点
)
// 径向渐变
RadialGradient(
center: Alignment.center,
radius: 0.8,
colors: [Colors.yellow, Colors.orange],
)
// 扇形渐变
SweepGradient(
colors: [Colors.red, Colors.green, Colors.blue, Colors.red],
)
4.2 TextStyle --- 文字样式
dart
TextStyle(
fontSize: 16, // 字号
fontWeight: FontWeight.w600, // 字重(w100~w900)
fontStyle: FontStyle.italic, // 斜体
color: Colors.black87, // 颜色
letterSpacing: 0.5, // 字间距
wordSpacing: 2.0, // 词间距
height: 1.6, // 行高(倍数)
decoration: TextDecoration.underline, // 下划线
decorationColor: Colors.red,
decorationStyle: TextDecorationStyle.dashed,
shadows: [
Shadow(
color: Colors.black26,
blurRadius: 4,
offset: Offset(1, 1),
),
],
overflow: TextOverflow.ellipsis,
)
样式继承与合并:
dart
// copyWith 在现有样式基础上修改部分属性
final baseStyle = const TextStyle(fontSize: 14, color: Colors.grey);
final titleStyle = baseStyle.copyWith(fontSize: 18, fontWeight: FontWeight.bold);
// merge 合并两个样式
final merged = baseStyle.merge(const TextStyle(color: Colors.black));
4.3 ThemeData --- 全局主题配置
在 MaterialApp 的 theme 属性中配置全局主题,避免到处硬编码颜色和样式。
dart
MaterialApp(
theme: ThemeData(
// 颜色方案(Flutter 3.x 推荐用 ColorScheme)
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.light,
),
useMaterial3: true,
// 文字主题
textTheme: const TextTheme(
displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.w400),
headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w500),
bodyLarge: TextStyle(fontSize: 16, height: 1.6),
bodyMedium: TextStyle(fontSize: 14, color: Colors.black87),
labelSmall: TextStyle(fontSize: 11, letterSpacing: 0.5),
),
// 按钮主题
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
),
// 输入框主题
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
),
// 卡片主题
cardTheme: CardTheme(
elevation: 2,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
),
// AppBar 主题
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
),
// 深色主题
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.dark,
),
useMaterial3: true,
),
themeMode: ThemeMode.system, // 跟随系统
home: const MyHomePage(),
)
在代码中使用主题:
dart
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
final textTheme = theme.textTheme;
return Container(
color: colorScheme.surface,
child: Text(
'标题',
style: textTheme.headlineMedium,
),
);
}
局部主题覆盖:
dart
// 只修改局部区域的主题,不影响全局
Theme(
data: Theme.of(context).copyWith(
iconTheme: const IconThemeData(color: Colors.red, size: 24),
),
child: Row(
children: const [
Icon(Icons.star), // 红色
Icon(Icons.favorite), // 红色
],
),
)
五、综合实战示例
下面通过一个商品卡片组件,综合运用本阶段所学知识:
dart
class ProductCard extends StatefulWidget {
final String title;
final String imageUrl;
final double price;
final double rating;
const ProductCard({
super.key,
required this.title,
required this.imageUrl,
required this.price,
required this.rating,
});
@override
State<ProductCard> createState() => _ProductCardState();
}
class _ProductCardState extends State<ProductCard> {
bool _isFavorite = false;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Container(
decoration: BoxDecoration(
color: theme.colorScheme.surface,
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.08),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 图片区域(Stack 实现收藏按钮覆盖)
Stack(
children: [
ClipRRect(
borderRadius: const BorderRadius.vertical(
top: Radius.circular(16),
),
child: Image.network(
widget.imageUrl,
height: 160,
width: double.infinity,
fit: BoxFit.cover,
),
),
Positioned(
top: 8,
right: 8,
child: GestureDetector(
onTap: () => setState(() => _isFavorite = !_isFavorite),
child: Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.9),
shape: BoxShape.circle,
),
child: Icon(
_isFavorite ? Icons.favorite : Icons.favorite_border,
color: _isFavorite ? Colors.red : Colors.grey,
size: 20,
),
),
),
),
],
),
// 信息区域
Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.title,
style: theme.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 8),
// 评分行
Row(
children: [
const Icon(Icons.star, color: Colors.amber, size: 16),
const SizedBox(width: 4),
Text(
widget.rating.toStringAsFixed(1),
style: theme.textTheme.bodySmall,
),
const Spacer(),
// 价格
RichText(
text: TextSpan(
children: [
TextSpan(
text: '¥',
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.error,
),
),
TextSpan(
text: widget.price.toStringAsFixed(0),
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: theme.colorScheme.error,
),
),
],
),
),
],
),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
child: const Text('加入购物车'),
),
),
],
),
),
],
),
);
}
}
六、常见问题与最佳实践
性能陷阱
- 避免在 build() 中创建对象 :
TextStyle()、BoxDecoration()等应提取为const或移到 class 级别。 - ListView 大数据用 builder :
ListView(children: [...])会一次性渲染所有 Widget;ListView.builder是懒加载。 - const Widget :凡是不依赖运行时数据的 Widget,加
const关键字,可复用实例,减少重建。
Widget 选择原则
- 需要背景色 + 无子 Widget →
ColoredBox(比 Container 轻量) - 只需内边距 →
Padding(比 Container 轻量) - 只需居中 →
Center(比Align(alignment: Alignment.center)语义更清晰) - 文本间距 →
SizedBox优于Padding(语义更明确)
调试工具
dart
// 调试布局,显示边界线
debugPaintSizeEnabled = true;
// 打印 Widget 树
debugDumpApp();
// 性能叠加层(帧耗时)
// 在 MaterialApp 中开启
showPerformanceOverlay: true,
总结
本阶段涵盖了 Flutter 基础 Widget 的核心内容:
- 理解三树架构是优化性能、排查问题的理论基础
- StatelessWidget / StatefulWidget 的正确选择直接影响代码架构
- 布局 Widget 的组合是构建复杂 UI 的关键,Row/Column/Stack/Expanded 是最常用的四剑客
- BoxDecoration + TextStyle + ThemeData 三者配合,实现统一、优雅的视觉设计
下一阶段将进入状态管理 与路由导航,届时会大量运用本阶段的 Widget 知识作为基础。建议在继续之前,动手实现 2~3 个完整的页面(如登录页、商品列表页、个人中心页),巩固所学内容。