*� Flutter Widget 复用完整总结(终极版)
🎯 1. StatelessWidget ( stl )是否会复用?
*� 结论: StatelessWidget 实例不会复用,但 Element 可能会复用!
*� StatelessWidget 在 setState() 时的行为
- Flutter 不会复用
StatelessWidget,每次setState()后都会重新创建Widget实例 - 但是**
StatelessWidget的Element并不会被销毁,而是复用** - Flutter 只是用新的
StatelessWidget来替换Element中的oldWidget
✅ 示例
class StaticText extends StatelessWidget {
StaticText() {
print("❗StaticText 被创建了!");
}
@override
Widget build(BuildContext context) {
print("🔄 StaticText.build() 被调用了!");
return const Text("Hello World");
}
}
🚀 点击按钮 setState()
setState(() {});
📢 日志输出
❗StaticText 被创建了! <-- `StatelessWidget` 重新创建
🔄 StaticText.build() 被调用了! <-- `build()` 重新执行
📌 StatelessWidget 本身被销毁并重新创建,但 Element 不变!
🎯 2. StatefulWidget ( stf )如何复用?
*� 结论: StatefulWidget 不会复用,但 State 和 Element ****可以 复用!
*� StatefulWidget 在 setState() 时的行为
StatefulWidget本身会被销毁并重新创建- 但是
State不会被销毁,它会在Element中复用 - Flutter 只是让
State的build()重新执行,不会创建新的State
✅ 示例
class Counter extends StatefulWidget {
Counter() {
print("❗Counter 被创建了!");
}
@override
_CounterState createState() {
print("🎯 CounterState 被创建了!");
return _CounterState();
}
}
class _CounterState extends State<Counter> {
int count = 0;
@override
Widget build(BuildContext context) {
print("🔄 Counter.build() 被调用了!");
return Column(
children: [
Text("计数器: $count"),
ElevatedButton(
onPressed: () {
setState(() {
count++;
});
},
child: const Text("增加"),
),
],
);
}
}
🚀 点击按钮 setState()
🔄 Counter.build() 被调用了!
📢 日志输出
❗Counter 被创建了!
🎯 CounterState 被创建了! <-- `State` 只会创建一次
🔄 Counter.build() 被调用了! <-- `build()` 重新执行
📌 StatefulWidget 本身被销毁并重新创建,但 State 复用了!
🎯 3. Element 在 StatefulWidget 和 StatelessWidget 中的作用
*� Element 在 setState() 时如何复用
- Flutter 主要依赖
Element树来管理Widget,而不是Widget 树 - 如果
runtimeType和Key没有变,Flutter 会复用Element - 如果
Widget类型发生了变化,Flutter 会销毁旧Element,创建新Element
✅ 示例
@override
Widget build(BuildContext context) {
return toggle ? Container() : SizedBox(); // `runtimeType` 变了,Element 无法复用!
}
📢 点击 setState() 触发切换
Container() → SizedBox() <-- `runtimeType` 不同,不能复用 `Element`
✅ 正确写法(保证 Element 复用)
@override
Widget build(BuildContext context) {
return Container(
key: ValueKey("same-widget"), // 🌟 添加 Key,保证 `Element` 复用
child: Text("Hello"),
);
}
📢 现在即使 setState() ,Flutter 也不会销毁 Element ,而是复用它!
🎯 4. runtimeType 和 Key 如何帮助复用?
*� 结论:Flutter 复用 Widget 主要依赖 runtimeType 和 Key
runtimeType相同,Flutter 可以 复用Key相同,即使Widget位置变化,Flutter 仍然 可以 复用runtimeType不同,Flutter 无法 复用Element,会创建新的
✅ 示例
@override
Widget build(BuildContext context) {
return Column(
children: [
toggle ? Container() : SizedBox(), // ❌ `runtimeType` 不同,不能复用 `Element`
],
);
}
*� Key 让 Widget 复用,即使位置发生变化
@override
Widget build(BuildContext context) {
return Column(
children: toggle
? [MyWidget("A", key: ValueKey("A")), MyWidget("B", key: ValueKey("B"))]
: [MyWidget("B", key: ValueKey("B")), MyWidget("A", key: ValueKey("A"))],
);
}
📢 加 Key 后,Flutter 仍然可以复用 Element ,提高性能!
🔥 最终总结(修正后的版本)
| 行为 | StatelessWidget (stl) | StatefulWidget (stf) |
|---|---|---|
| Widget 是否会复用? | ❌ Widget 每次 build() 都会新建 | ❌ Widget 每次 build() 都会新建 |
| Element 是否会复用? | ✅ 如果类型和 Key 没变,Element 仍然复用 | ✅ Element 仍然复用 |
| State 是否会复用? | ❌ 没有 State,无法复用 | ✅ State 会复用,不会被销毁 |
setState() 触发时的行为 | 创建新 Widget,但 Element 可能复用 | 创建新 Widget,但 State 仍然保持,Element 复用 |
| 如何优化? | ✅ const 避免新实例的创建 | ✅ Key 确保 State 复用 |
📌 最重要的知识点
1️⃣ StatelessWidget 和 StatefulWidget 每次 build() 触发都会新建 Widget 对象,但 Element 可能被复用!
2️⃣ StatelessWidget 的 Element 只要 runtimeType 和 Key 没变,Flutter 就会尝试复用!
3️⃣ StatefulWidget 的 State 只要 runtimeType 和 Key 没变,就不会被销毁,会复用!
4️⃣ const 关键字主要优化 Widget 实例的创建,并不直接影响 Element 复用!
5️⃣ 使用 Key 可确保 State 复用,避免不必要的重建!
✨ *� 这就是 Flutter Widget 复用的完整解析!!! 🚀🚀🚀