You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter GetX嵌套ListView.builder()报错及UI不更新问题求助

问题解决方法

问题1:添加第二个Widget1触发build期间更新错误

原因

  • 在Widget1的build方法中直接调用controller.setListWidget2(mykey),该方法修改了RxMap并触发UI更新,但此时Widget1正处于build流程中,违反了框架的构建规则。
  • HomePage的build方法中重复执行控制器注入操作,每次build都会触发Get.put,容易引发状态混乱。

修复步骤

  1. 将Widget1中初始化列表的逻辑从build方法移到构造函数中,避免在构建阶段修改响应式变量:
const Widget1({required this.mykey, super.key}) {
  controller.setListWidget2(mykey);
}
  1. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:04:03