本文同步发表于微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
1. 示例
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Color colorA = Colors.blue;
Color colorB = Colors.red;
@override
Widget build(BuildContext context) {
return Column(
children: [
Container(
width: 100,
height: 100,
color: colorA,
),
Container(
width: 100,
height: 100,
color: colorB,
),
ElevatedButton(
onPressed: () {
// 直接修改状态
colorA = Colors.green; // A组件背景色变绿
colorB = Colors.yellow; // B组件背景色变黄
// 稍后调用 setState
Future.delayed(Duration(milliseconds: 500), () {
setState(() {});
});
},
child: Text('修改颜色'),
),
],
);
}
}
2. 发生了什么?
2.1 内存中的状态确实改变了
当执行 colorA = Colors.green 时,内存中 colorA 变量的值确实立即改变了。这个改变是立即生效的,不需要等待 setState。
2.2 但界面不会立即更新
Flutter 的界面渲染基于 Widget 树的重建。流程如下:
直接修改颜色变量 → 变量值已改变 → 界面未重建 → 看不到变化
↓
调用 setState → 触发 build 方法 → 界面重建 → 看到变化
2.3 build 方法的作用
当调用 setState 时:
-
标记状态为 "dirty"(脏状态)
-
安排下一帧重建
-
下一帧到来时,重新执行
build方法 -
build方法中读取的是当前最新的变量值 -
使用新值构建新的 Widget 树
3. 结果验证
onPressed: () {
print('修改前: colorA = $colorA');
colorA = Colors.green;
colorB = Colors.yellow;
print('修改后: colorA = $colorA'); // 这里会输出 Colors.green
// 此时界面上仍然是蓝色和红色
// 因为 Widget 树还没有重建
setState(() {
// 空的 setState 也会触发重建
});
// 下一帧时,build 方法会读取新的 colorA 值
// 界面会更新为绿色和黄色
}
4. 如果是独立组件:
class ColorBox extends StatefulWidget {
final Color initialColor;
ColorBox({required this.initialColor});
@override
_ColorBoxState createState() => _ColorBoxState();
}
class _ColorBoxState extends State<ColorBox> {
late Color _color;
@override
void initState() {
super.initState();
_color = widget.initialColor;
}
void changeColor(Color newColor) {
_color = newColor; // 直接修改
// 如果这里不调用 setState,界面不会更新
}
@override
Widget build(BuildContext context) {
return Container(
width: 100,
height: 100,
color: _color,
);
}
}
在这种情况下:
-
直接调用
colorBox.changeColor(Colors.green)会修改内存中的值 -
但如果没有调用该组件的
setState,界面不会更新 -
即使父组件调用了
setState,子组件的状态也不会自动更新
5. 结论
| 操作 | 内存中的值 | 界面显示 | 说明 |
|---|---|---|---|
| 直接修改变量 | 立即改变 | 不改变 | 变量值变了,但 Widget 树没重建 |
调用 setState | 保持不变 | 更新为新值 | 触发重建,读取最新的变量值 |
先修改变量再 setState | 改变 | 更新为新值 | 标准做法 |
setState 的作用:不是修改状态,而是通知框架状态已改变,需要重建 UI。
6. 建议
// 推荐:在 setState 的回调中修改变量
setState(() {
colorA = Colors.green;
colorB = Colors.yellow;
});
// 不推荐:先修改变量再调用空 setState
colorA = Colors.green;
colorB = Colors.yellow;
setState(() {}); // 空的 setState 虽然可以,但不够清晰
// 错误做法:只修改变量不调用 setState
colorA = Colors.green; // 界面永远不会更新
1106

被折叠的 条评论
为什么被折叠?



