目录
- 1. 什么是Widget?Flutter中的Widget分为哪几类?
- 2. StatelessWidget和StatefulWidget的区别
- 3. StatefulWidget生命周期
- 4. 什么是BuildContext?
- 5. 如何优化Widget重建?
- 6. Flutter布局机制
- 7. Row/Column的主轴和交叉轴
- 8. Expanded vs Flexible
- 9. Key的作用与使用场景
- 10. 国际化(i18n)实现
1. 什么是Widget?Flutter中的Widget分为哪几类?
Widget:Flutter应用的基础构建单元,描述UI元素的配置(如布局、样式等)。
- 不可变性:Widget不可变,重建时生成新实例
- 声明式UI:通过嵌套Widget树描述界面
主要分类:
| 类别 | 特点 | 示例 |
|---|---|---|
| StatelessWidget | 无状态,属性不可变 | Text, Icon, Container |
| StatefulWidget | 有状态,可动态更新 | Checkbox, TextField, Slider |
| InheritedWidget | 数据共享,跨层级传递 | Theme, MediaQuery |
| ProxyWidget | 父Widget代理 | ParentDataWidget |
| RenderObjectWidget | 底层渲染控制 | Opacity, Transform |
// Widget树示例
Container( // 布局Widgetpadding: EdgeInsets.all(10),child: Column( // 布局Widgetchildren: [Text('Hello', style: TextStyle(fontSize: 20)), // 无状态WidgetStatefulCounter() // 有状态Widget],),
)
2. StatelessWidget和StatefulWidget的区别
| 特性 | StatelessWidget | StatefulWidget |
|---|---|---|
| 状态管理 | ❌ 无内部状态 | ✅ 可维护可变状态 |
| 重建机制 | 完全重建 | 通过State对象保留状态 |
| 生命周期 | 简单(仅build) | 复杂(initState/didUpdateWidget等) |
| 性能 | 更高 | 较低(需维护State) |
| 使用场景 | 静态内容 | 交互式组件(表单/动画) |
典型场景:
- Stateless:显示静态文本/图标
- Stateful:计数器、开关按钮
3. StatefulWidget生命周期
关键方法:
- initState:初始化状态(调用一次)
- didChangeDependencies:依赖变化时调用(如InheritedWidget更新)
- build:构建UI(必实现)
- didUpdateWidget:父Widget重建时触发
- setState:通知框架状态变化(触发rebuild)
- deactivate:从树中移除(可能重新插入)
- dispose:永久销毁,释放资源
⚠️ 注意:避免在build()中做耗时操作!
4. 什么是BuildContext?
BuildContext是Widget在树中位置的引用,核心作用:
查找祖先Widget:
ThemeData theme = Theme.of(context); // 获取最近的Theme
导航操作:
Navigator.push(context, MaterialPageRoute(...));
Widget状态管理:
ScaffoldState scaffold = Scaffold.of(context);
scaffold.openDrawer(); // 打开抽屉
重要原则:
- 每个Widget有独立BuildContext
- Context在Element创建时生成
- 不可缓存Context(可能失效)
5. 如何优化Widget重建?
| 优化方案 | 实现方式 | 效果 |
|---|---|---|
| const构造函数 | const Text('Hello') | 避免重复创建相同实例 |
| 拆分Widget树 | 将易变部分拆为子Widget | 减少重建范围 |
| 使用StatelessWidget | 优先用于静态内容 | 降低状态管理开销 |
| Keys的正确使用 | 为列表项/状态Widget设置Key | 精确控制更新 |
| shouldRebuild | @override bool updateShouldNotify | 控制InheritedWidget更新范围 |
代码示例:
// 优化前:整个Card重建
Widget build() {return Card(child: HeavyContent(), // 重组件);
}// 优化后:仅变化部分重建
Widget build() {return const Card( // const避免重建child: _HeavyContent(), // 拆分为独立Widget);
}
6. Flutter布局机制
布局流程(自顶向下):
- 父Widget传递约束(constraints: min/max宽高)
- 子Widget确定自身尺寸
- 父Widget定位子Widget(根据alignment/offset)
核心原则:
- 约束驱动:父给子约束,子不能超出约束
- 递归布局:深度优先遍历Widget树
- 单次布局:每帧最多布局一次
// 布局示例
ConstrainedBox(constraints: BoxConstraints(minWidth: 100, maxHeight: 200), // 父约束child: Container(width: 150, // 子确定尺寸(在约束范围内)height: 180,),
)
7. Row/Column的主轴和交叉轴
| 布局组件 | 主轴方向 | 交叉轴方向 |
|---|---|---|
| Row | 水平(X轴) | 垂直(Y轴) |
| Column | 垂直(Y轴) | 水平(X轴) |
主轴对齐(mainAxisAlignment):
start/end/center/spaceBetween
交叉轴对齐(crossAxisAlignment):
stretch/baseline/start
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, // 主轴均匀分布crossAxisAlignment: CrossAxisAlignment.center, // 交叉轴居中children: [ ... ],
)
8. Expanded vs Flexible
| 特性 | Expanded | Flexible |
|---|---|---|
| 继承关系 | Flexible的子类 | 基础类 |
| flex默认值 | flex=1 | flex=1(可自定义) |
| 空间占用 | 强制填满剩余空间 | 按需占用空间 |
| fit行为 | 固定FlexFit.tight | 可配置FlexFit.loose |
使用场景:
Row(children: [Container(width: 50), // 固定宽度Expanded( // 占满剩余宽度child: Text('Expanded Content'),),Flexible( // 按内容宽度占用fit: FlexFit.loose,child: Text('Flexible'),)],
)
9. Key的作用与使用场景
Key的作用:
唯一标识Widget,帮助框架在重建时区分相同类型的Widget
使用场景:
| Key类型 | 适用场景 |
|---|---|
| ValueKey | 列表项(值唯一时) |
| ObjectKey | 复杂对象的列表 |
| UniqueKey | 强制重建(如动画重置) |
| GlobalKey | 跨组件访问状态 |
示例:
ListView.builder(itemBuilder: (ctx, index) {return ListTile(key: ValueKey(items[index].id), // 基于id标识title: Text(items[index].name),);}
)
何时需要Key:
- 动态列表(增删改操作)
- 保留状态(如表单输入框)
- 需要跨组件访问状态
10. 国际化(i18n)实现
实现步骤:
- 添加依赖:
dependencies:flutter_localizations:sdk: flutterintl: ^0.17.0
- 创建ARB文件:
**lib/l10n/app_en.arb**
{"hello": "Hello!","@hello": {"description": "欢迎语"}
}
- 生成本地化类:
flutter gen-l10n
- 配置MaterialApp:
MaterialApp(localizationsDelegates: AppLocalizations.localizationsDelegates,supportedLocales: AppLocalizations.supportedLocales,
)
- 使用翻译:
Text(AppLocalizations.of(context)!.hello)