Flutter中GridView选图及Slider滑动时避免FutureBuilder重建的方法
问题根因
- FutureBuilder的
future参数直接绑定了实时执行的fetchAndSetPlaces()方法,每次页面触发setState(选中图片、拖动Slider都会触发)都会导致该方法重新执行,重复拉取数据库数据,同时触发页面重绘导致选中状态被覆盖。 - 选中状态的更新逻辑没有和数据加载逻辑解耦,重复加载数据时状态无法持久保留。
解决方案
1. 缓存Future请求,避免重复拉取数据
在当前页面的State类中定义一个Future成员变量,仅在页面初始化时执行一次数据拉取,后续页面重build不会重新触发数据库请求,修改后的完整代码如下:
class _YourPageState extends State<YourPage> { late Future _loadImagesFuture; int? selectedCard; // 选中下标,定义为State的成员变量 double _currentSliderValue = 0; @override void initState() { super.initState(); // 仅在初始化时执行一次数据拉取,缓存Future结果 _loadImagesFuture = Provider.of<Images>(context, listen: false).fetchAndSetPlaces(); } // 选中逻辑调整,传入index更新选中状态 void add(int index, File image) { // 保留你原有业务逻辑 setState(() { selectedCard = index; }); } // 保留你原有的计算GridView列数的逻辑 int getSize(double value) { return value.round() + 2; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("Image"), elevation: 0, actions: <Widget>[ IconButton( icon: const Icon( Icons.add, color: Colors.white, ), onPressed: () => scan(context, selectLocation.id), ) ], backgroundColor: Colors.transparent, ), // 替换为缓存的_loadImagesFuture,不会重复执行拉取逻辑 body: FutureBuilder( future: _loadImagesFuture, builder: (ctx, snapshot) => snapshot.connectionState == ConnectionState.waiting ? const Center( child: CircularProgressIndicator(), ) : Column( children: [ Expanded( flex: 2, child: Container( padding: const EdgeInsets.only( top: 30, bottom: 1, left: 40, right: 40), child: Consumer<Images>( builder: (ctx, titles, ch) => GridView.builder( physics: const ScrollPhysics(), itemCount: titles.items.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: getSize(_currentSliderValue), mainAxisSpacing: 50, childAspectRatio: 0.8, crossAxisSpacing: 5, ), itemBuilder: (ctx, index) { return GestureDetector( onTap: () => add(index, titles.items[index].image), child: Container( color: selectedCard == index ? Colors.blue : Colors.green, child: Image.file(titles.items[index].image), ), ); }, ), ), ), ), Expanded( child: Container( padding: const EdgeInsets.only(left: 30, right: 30), child: Theme( data: Theme.of(context).copyWith( accentTextTheme: TextTheme( bodyText2: const TextStyle(color: Colors.white)), ), child: Slider( inactiveColor: Colors.purple, activeColor: Colors.purple, value: _currentSliderValue, min: 0, max: 2, divisions: 2, label: _currentSliderValue.round().toString(), onChanged: (double value) { setState(() { _currentSliderValue = value; }); }, ), ), ), ), ], ), ), ); } }
2. 多选场景优化
如果需要支持多选图片,可将selectedCard改为集合类型存储选中下标,修改逻辑如下:
// 定义选中下标集合 Set<int> selectedIndexes = {}; void add(int index, File image) { setState(() { if (selectedIndexes.contains(index)) { selectedIndexes.remove(index); } else { selectedIndexes.add(index); } }); } // 背景色判断逻辑修改为 color: selectedIndexes.contains(index) ? Colors.blue : Colors.green,
内容的提问来源于stack exchange,提问作者cvsrt
相关产品推荐
相关产品推荐

