Flutter Stack中子组件为列表项时调用setState状态不更新问题
问题原因
这个现象是Flutter Widget的不可变特性和当前的列表缓存逻辑共同导致的:
- 你在State类中声明的
List<Widget> list存储的是已经创建完成的Widget实例,仅在第一次build、list为空时往里面添加了一次组件,此时组件里的_counter值已经固定为初始的0。 - 后续调用
setState触发重绘时,你没有更新list里的Widget实例,Flutter会直接复用缓存的旧Widget,自然不会用到最新的_counter值。 - 直接写在Stack children里的组件每次build都会重新创建,会读取最新的
_counter值,所以可以正常更新。
解决方案
不要直接缓存Widget实例,改为维护动态组件的配置数据,每次build时根据配置动态生成Widget列表即可,既能支持动态增减,也能保证状态正常响应更新。
修改后的参考代码如下:
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } // 定义组件配置的模型类,用来存每个动态组件的参数 class PositionedTextConfig { final double left; final double top; // 其他自定义参数都可以加在这里 PositionedTextConfig({required this.left, required this.top}); } class _MyHomePageState extends State<MyHomePage> { double _counter = 0; // 改为存配置数据,不存Widget实例 List<PositionedTextConfig> configList = []; void _incrementCounter() { setState(() { _counter++; // 如果要新增组件,往配置列表加数据即可 // 示例:每点击3次加一个新的文本 // if(_counter %3 ==0) { // configList.add(PositionedTextConfig(left: 100, top: 100 + _counter*20)); // } }); } @override void initState() { super.initState(); // 初始添加第一个动态组件的配置 configList.add(PositionedTextConfig(left: 100, top: 100)); } @override Widget build(BuildContext context) { // 每次build的时候,根据配置列表动态生成所有Widget List<Widget> dynamicChildren = configList.map((config) { return Positioned( left: config.left, top: config.top, child: Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ); }).toList(); return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Stack( children: [ Positioned( left: 100, top: 0, child: Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ), // 把动态生成的组件列表展开加入 ...dynamicChildren ], ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: Icon(Icons.add), ), ); } }
如果确实需要直接缓存Widget实例,每次状态更新时同步更新列表中对应的Widget实例再调用setState也可以实现,但这种方式维护成本更高,更推荐用配置数据生成的方案。
内容的提问来源于stack exchange,提问作者Ηλίας Λάμπρου
相关产品推荐
相关产品推荐

