Flutter GetX框架下CheckboxListTile状态更新后UI未同步刷新问题咨询
问题成因
- 你修改的是
expiringContractStatus可观察列表内部Map的属性,没有改变列表本身的引用,GetX的响应式监听默认感知不到集合内部元素的属性变更,只会监听集合增删、整体替换这类改变引用的操作。 - 视图层没有用
Obx包裹需要响应状态变化的组件,即使obs状态更新,没有Obx监听也不会触发UI重绘;同时你混用了响应式obs和简单状态管理的update()方法,逻辑不统一。 - 你在onChanged回调里额外调用的
controller.update()没有配合GetBuilder使用,所以该调用不会触发UI更新。
解决方法
两种方案二选一即可,不要混用两种状态管理逻辑:
方案1:纯响应式方案(推荐,适配obs使用规范)
第一步:修改Controller的itemChange方法
修改属性后主动触发列表更新通知,或者直接替换对应索引的Map对象,让obs感知到变更:
void itemChange (bool value, int index) { // 方式1:替换对应索引的Map,触发obs自动感知 expiringContractStatus[index] = { ...expiringContractStatus[index], "isCheck": value }; // 方式2:不想替换对象的话,可以调用refresh()主动触发通知 // expiringContractStatus[index]["isCheck"] = value; // expiringContractStatus.refresh(); // 注意不要调用update(),响应式模式不需要该方法 }
第二步:修改视图层,用Obx包裹需要响应更新的区域
将生成CheckboxListTile的逻辑用Obx包裹,监听obs的变化:
ExpansionTile( title: Text("Contract Status".tr, style: Get.textTheme.bodyText2), // 用Obx包裹children生成逻辑,监听obs状态变更 children: Obx(() => List.generate(controller.expiringContractStatus.length, (index) { var _expiringContractStatus = controller.expiringContractStatus.elementAt(index); return CheckboxListTile( controlAffinity: ListTileControlAffinity.trailing, value: _expiringContractStatus["isCheck"], onChanged: (value) { controller.itemChange(value, index); // 删除这里的controller.update(),响应式模式不需要 }, title: Text( _expiringContractStatus["title"], style: Get.textTheme.bodyText1, overflow: TextOverflow.fade, softWrap: false, maxLines: 1, ), ); })), initiallyExpanded: true, )
方案2:简单状态管理方案(适配update()使用规范)
第一步:修改Controller的变量定义,去掉.obs
// 不需要.obs,直接用普通列表 final expiringContractStatus = <Map>[ { "title": "aaa", "isCheck": false }, { "title": "bbb", "isCheck": false }, { "title": "ccc", "isCheck": false } ];
第二步:视图层用GetBuilder包裹需要更新的区域
GetBuilder<SearchController>( builder: (controller) => ExpansionTile( title: Text("Contract Status".tr, style: Get.textTheme.bodyText2), children: List.generate(controller.expiringContractStatus.length, (index) { var _expiringContractStatus = controller.expiringContractStatus.elementAt(index); return CheckboxListTile( controlAffinity: ListTileControlAffinity.trailing, value: _expiringContractStatus["isCheck"], onChanged: (value) { controller.itemChange(value, index); }, title: Text( _expiringContractStatus["title"], style: Get.textTheme.bodyText1, overflow: TextOverflow.fade, softWrap: false, maxLines: 1, ), ); }), initiallyExpanded: true, ) )
该方案下Controller的itemChange方法里保留update()调用即可,无需额外修改。
内容的提问来源于stack exchange,提问作者Speeder
相关产品推荐
相关产品推荐

