Flutter GetX嵌套ListView.builder()报错及UI不更新问题求助
问题解决方法
问题1:添加第二个Widget1触发build期间更新错误
原因
- 在
Widget1的build方法中直接调用controller.setListWidget2(mykey),该方法修改了RxMap并触发UI更新,但此时Widget1正处于build流程中,违反了框架的构建规则。 HomePage的build方法中重复执行控制器注入操作,每次build都会触发Get.put,容易引发状态混乱。
修复步骤
- 将
Widget1中初始化列表的逻辑从build方法移到构造函数中,避免在构建阶段修改响应式变量:
const Widget1({required this.mykey, super.key}) { controller.setListWidget2(mykey); }
HomePage作为GetView<HomeController>,无需在build中重复注入控制器,直接使用controller即可;移除HomePage中final widget1Controller = Get.put(Widget1Controller());这行冗余代码。
问题2:添加Widget2后列表长度增加但界面无更新
原因
_mapListWidget2是RxMap,但内部存储的List<Widget2>并非响应式列表(RxList),向普通列表添加元素不会触发RxMap的状态更新,导致GetX无法感知变化并重建UI。
修复步骤
修改Widget1Controller,将内部列表改为RxList,确保元素变更能被响应式系统捕获:
class Widget1Controller extends GetxController { final RxMap<Key, RxList<Widget2>> _mapListWidget2 = <Key, RxList<Widget2>>{}.obs; void setListWidget2(Key mykey) { // 仅当key不存在时初始化,避免重复操作 if (!_mapListWidget2.containsKey(mykey)) { _mapListWidget2[mykey] = <Widget2>[].obs; } } void addWidget2(Widget2 newWidget2, Key mykey) { _mapListWidget2[mykey]?.add(newWidget2); } List<Widget2> getListWidget2(Key key) { return _mapListWidget2[key]?.toList() ?? <Widget2>[]; } }
完整修改后的代码
HomePage
class HomePage extends GetView<HomeController> { const HomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), floatingActionButton: FloatingActionButton( child: const Icon(Icons.add), onPressed: () { final mykey = GlobalKey(); controller.addWidget1(Widget1(mykey: mykey)); }, ), body: GetX<HomeController>( builder: (_) { return ListView.builder( itemBuilder: (context, index) { return controller.getWidget1[index]; }, itemCount: controller.getWidget1.length, ); }, ), ); } }
Widget1
class Widget1 extends GetView<Widget1Controller> { final Key mykey; const Widget1({required this.mykey, super.key}) { controller.setListWidget2(mykey); } @override Widget build(BuildContext context) { return GetX<Widget1Controller>( builder: (_) { return ExpansionTile( title: Container( color: Colors.blue, width: 50.0, height: 50.0, ), children: [ ListView.builder( itemBuilder: (context, index) { return controller.getListWidget2(mykey)[index]; }, itemCount: controller.getListWidget2(mykey).length, shrinkWrap: true, ), IconButton( onPressed: () { controller.addWidget2(const Widget2(), mykey); debugPrint("list: ${controller.getListWidget2(mykey).length}"); }, icon: const Icon(Icons.add), ) ], ); }, ); } }
Widget1Controller
class Widget1Controller extends GetxController { final RxMap<Key, RxList<Widget2>> _mapListWidget2 = <Key, RxList<Widget2>>{}.obs; void setListWidget2(Key mykey) { if (!_mapListWidget2.containsKey(mykey)) { _mapListWidget2[mykey] = <Widget2>[].obs; } } void addWidget2(Widget2 newWidget2, Key mykey) { _mapListWidget2[mykey]?.add(newWidget2); } List<Widget2> getListWidget2(Key key) { return _mapListWidget2[key]?.toList() ?? <Widget2>[]; } }
额外优化建议
可以在main中懒加载控制器,避免在页面中重复注入:
void main() { Get.lazyPut(() => HomeController()); Get.lazyPut(() => Widget1Controller()); runApp( const GetMaterialApp( home: HomePage(), ), ); }
内容的提问来源于stack exchange,提问作者Héctor
相关产品推荐
相关产品推荐

