Flutter 进阶
本节将介绍一些 Flutter 进阶概念,帮助你提升开发技能。
渲染原理
Flutter 使用 Skia(自 3.0 起逐步切换到 Impeller)渲染引擎直接绘制 UI,不使用原生组件。
Widget 树与 Element 树
- Widget 树: 描述 UI 的配置信息(不可变)
- Element 树: Widget 的实例化对象(可变)
- RenderObject 树: 负责实际渲染
理解渲染原理有助于优化 UI 性能,避免不必要的重建。
InheritedWidget - 数据传递
InheritedWidget 允许数据沿着 Widget 树向下传递,子 Widget 可以获取祖先的数据。
实例:自定义 InheritedWidget
// 定义数据容器
class MyData extends InheritedWidget {
final int value;
const MyData({
super.key,
required this.value,
required super.child,
});
// 便捷方法:获取最近的 MyData
static MyData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyData>()!;
}
// 判断是否需要重建子 Widget
@override
bool updateShouldNotify(MyData oldWidget) {
return value != oldWidget.value;
}
}
// 使用
class ParentWidget extends StatelessWidget {
const ParentWidget({super.key});
@override
Widget build(BuildContext context) {
return MyData(
value: 42,
child: const ChildWidget(),
);
}
}
class ChildWidget extends StatelessWidget {
const ChildWidget({super.key});
@override
Widget build(BuildContext context) {
// 获取祖先的 MyData
final myData = MyData.of(context);
return Text('Value: ${myData.value}');
}
}
class MyData extends InheritedWidget {
final int value;
const MyData({
super.key,
required this.value,
required super.child,
});
// 便捷方法:获取最近的 MyData
static MyData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<MyData>()!;
}
// 判断是否需要重建子 Widget
@override
bool updateShouldNotify(MyData oldWidget) {
return value != oldWidget.value;
}
}
// 使用
class ParentWidget extends StatelessWidget {
const ParentWidget({super.key});
@override
Widget build(BuildContext context) {
return MyData(
value: 42,
child: const ChildWidget(),
);
}
}
class ChildWidget extends StatelessWidget {
const ChildWidget({super.key});
@override
Widget build(BuildContext context) {
// 获取祖先的 MyData
final myData = MyData.of(context);
return Text('Value: ${myData.value}');
}
}
RepaintBoundary - 局部重绘
使用 RepaintBoundary 可以限制重绘区域,提高性能。
实例:RepaintBoundary 使用
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return RepaintBoundary(
child: Container(
// 这个区域的绘制不会影响外部
color: Colors.red,
child: const Text('独立区域'),
),
);
}
}
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
return RepaintBoundary(
child: Container(
// 这个区域的绘制不会影响外部
color: Colors.red,
child: const Text('独立区域'),
),
);
}
}
Keys 的深入理解
Keys 帮助 Flutter 识别 Widget,区分新 Widget 和已有 Widget。
ValueKey vs ObjectKey vs UniqueKey
| 类型 | 说明 |
|---|---|
| ValueKey | 使用值作为键(如 ID、数字、字符串) |
| ObjectKey | 使用对象引用作为键 |
| UniqueKey | 每次创建生成唯一键,破坏重建 |
CustomPainter - 自定义绘制
使用 CustomPainter 可以实现完全自定义的图形绘制。
实例:CustomPainter 使用
class CustomPainterExample extends StatelessWidget {
const CustomPainterExample({super.key});
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: MyCirclePainter(),
size: const Size(200, 200),
);
}
}
class MyCirclePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// 绘制圆形
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
final center = Offset(size.width / 2, size.height / 2);
final radius = size.width / 2 - 10;
canvas.drawCircle(center, radius, paint);
// 绘制边框
final borderPaint = Paint()
..color = Colors.black
..style = PaintingStyle.stroke
..strokeWidth = 2;
canvas.drawCircle(center, radius, borderPaint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
const CustomPainterExample({super.key});
@override
Widget build(BuildContext context) {
return CustomPaint(
painter: MyCirclePainter(),
size: const Size(200, 200),
);
}
}
class MyCirclePainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// 绘制圆形
final paint = Paint()
..color = Colors.blue
..style = PaintingStyle.fill;
final center = Offset(size.width / 2, size.height / 2);
final radius = size.width / 2 - 10;
canvas.drawCircle(center, radius, paint);
// 绘制边框
final borderPaint = Paint()
..color = Colors.black
..style = PaintingStyle.stroke
..strokeWidth = 2;
canvas.drawCircle(center, radius, borderPaint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return false;
}
}
Stream 和 Future
实例:Stream 用法
// 创建 Stream
Stream<int> countStream(int max) async* {
for (int i = 1; i <= max; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i; // 发送值
}
}
// 使用 StreamBuilder
class StreamExample extends StatelessWidget {
const StreamExample({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<int>(
stream: countStream(10),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text('计数: ${snapshot.data}');
} else if (snapshot.hasError) {
return Text('错误: ${snapshot.error}');
}
return const CircularProgressIndicator();
},
);
}
}
Stream<int> countStream(int max) async* {
for (int i = 1; i <= max; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i; // 发送值
}
}
// 使用 StreamBuilder
class StreamExample extends StatelessWidget {
const StreamExample({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<int>(
stream: countStream(10),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text('计数: ${snapshot.data}');
} else if (snapshot.hasError) {
return Text('错误: ${snapshot.error}');
}
return const CircularProgressIndicator();
},
);
}
}
总结
本 Flutter 入门教程涵盖了以下内容:
- Flutter 安装和环境配置
- Widget 基础(StatelessWidget 和 StatefulWidget)
- 布局系统(Row、Column、Stack)
- 用户输入处理
- 状态管理(setState、Provider)
- 网络请求和数据存储
- 导航和路由
- 测试和发布
继续深入学习可以关注:
- BLoC 模式
- Riverpod 状态管理
- GetX 路由和状态管理
- Flutter 性能优化
- Flutter Web 和桌面开发
点我分享笔记