Flutter中如何实现ListView.builder()的动态更新?
问题解决方法
根因说明
- Dart中Map属于引用类型,直接修改Map内部的键值对不会改变Map本身的内存地址,
setState检测不到状态引用变更,就不会触发组件重绘,所以只有热重载强制重建全页才会生效 myMap如果定义为全局变量,没有绑定到对应State的生命周期,也会导致State无法感知状态变化- 你现有代码存在逻辑冲突:ListView的渲染条件是
myMap.values.elementAt(index) == true才显示文本,但是修改时给myMap[1]赋值的是字符串,修改后值永远不等于true,会一直显示空容器
修复步骤
- 将
myMap移动到State类内部作为私有状态变量,不要定义为全局变量 - 修改Map值时先拷贝生成新的Map对象,替换原状态变量的引用,再调用
setState - 统一Map值的类型,避免判断条件失效
完整示例代码
import 'package:flutter/material.dart'; class NextWidget extends StatefulWidget { NextWidget({Key? key}) : super(key: key); @override _NextWidgetState createState() => _NextWidgetState(); } class _NextWidgetState extends State<NextWidget> { // 状态变量放在State内部,初始化示例 Map<int, dynamic> myMap = { 1: true, 2: false, 3: true, }; @override Widget build(BuildContext context) { return Column( children: [ // ListView放在同一个State的build方法内,使用内部的myMap变量 ListView.builder( physics: NeverScrollableScrollPhysics(), itemCount: myMap.length, shrinkWrap: true, itemBuilder: (context, index) { return myMap.values.elementAt(index) == true ? Container( padding: EdgeInsets.only(left: 20, right: 20, top: 20), child: Container(child: Text(myMap.keys.elementAt(index).toString())), ) : Container(); }, ), MaterialButton( onPressed: () { setState(() { // 先拷贝原Map生成新对象,修改后替换原状态变量 final newMap = Map.of(myMap); // 如果要保留显示逻辑,值要设为bool类型;如果要修改显示的文本,可以调整渲染逻辑读取value展示 newMap[2] = true; myMap = newMap; }); }, child: Text('Modify'), ) ], ); } }
如果你的ListView和修改按钮在不同的组件中,可以优先使用ValueNotifier配合ValueListenableBuilder实现局部刷新,比StreamBuilder语法更简单:
// 定义ValueNotifier final myMapNotifier = ValueNotifier<Map<int, dynamic>>({1: true, 2: false}); // 列表部分用ValueListenableBuilder包裹 ValueListenableBuilder<Map<int, dynamic>>( valueListenable: myMapNotifier, builder: (context, myMap, child) { return ListView.builder( physics: NeverScrollableScrollPhysics(), itemCount: myMap.length, shrinkWrap: true, itemBuilder: (context, index) { return myMap.values.elementAt(index) == true ? Container( padding: EdgeInsets.only(left: 20, right: 20, top: 20), child: Container(child: Text(myMap.keys.elementAt(index).toString())), ) : Container(); }, ); } ); // 修改值的地方 MaterialButton( onPressed: () { final newMap = Map.of(myMapNotifier.value); newMap[2] = true; myMapNotifier.value = newMap; }, child: Text('Modify'), )
内容的提问来源于stack exchange,提问作者Hamza Amr
相关产品推荐
相关产品推荐

