Flutter:下载完成后ListView索引重置问题的解决办法
解决方案
问题根源在于:当切换到CircularProgressIndicator时,原有的ListView组件会被完全销毁,下载完成重新构建ListView时,它会默认回到初始滚动位置(索引0)。我们可以通过ScrollController保存并恢复滚动位置,无需额外状态管理库,仅在当前State中处理即可。
具体实现步骤
- 在State类中定义
ScrollController实例,以及用于保存滚动偏移量的变量 - 触发下载操作前,记录当前ListView的滚动位置
- 下载完成重新显示ListView后,通过控制器恢复之前的滚动位置
- 在State销毁时释放
ScrollController,避免内存泄漏
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; class ProductsListView extends StatefulWidget { const ProductsListView({ Key? key, required this.productsInfosList, }) : super(key: key); final List<ProductInfosModels> productsInfosList; @override State<ProductsListView> createState() => _ProductsListViewState(); } class _ProductsListViewState extends State<ProductsListView> { bool flagForCircularProgressIndicator = false; // 定义滚动控制器和保存偏移量的变量 final ScrollController _scrollController = ScrollController(); double _previousScrollOffset = 0.0; @override void dispose() { // 销毁时释放控制器 _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return flagForCircularProgressIndicator ? Center(child: CircularProgressIndicator()) : ListView.separated( // 给ListView绑定控制器 controller: _scrollController, itemBuilder: (BuildContext context, int index) { return InkWell( onTap: () async { // 记录当前滚动位置 _previousScrollOffset = _scrollController.offset; setState(() { flagForCircularProgressIndicator = true; }); await ProductsNetworking().downloadProductDocument( widget.productsInfosList[index].productId.toString()); setState(() { flagForCircularProgressIndicator = false; }); // 组件重建完成后恢复滚动位置 WidgetsBinding.instance.addPostFrameCallback((_) { _scrollController.jumpTo(_previousScrollOffset); }); }, child: Padding( padding: const EdgeInsets.fromLTRB(8, 25, 8, 25), child: Row( children: [ Padding( padding: const EdgeInsets.only(right: 8.0), child: Container( width: 140, child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Icon(FontAwesomeIcons.scaleBalanced), SizedBox(height: 15), Text(widget.productsInfosList[index].id), ], ), ), ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(widget.productsInfosList[index].productName), SizedBox(height: 10.0), Text(widget.productsInfosList[index].productionDate), SizedBox(height: 10.0), ], ), ), Container( width: 60, child: Icon(Icons.download)) ], ), ), ); }, separatorBuilder: (BuildContext context, int index) => const Divider( color: Colors.black54, ), itemCount: widget.productsInfosList.length, ); } }
额外优化说明
如果想要更平滑的滚动恢复效果,可以将jumpTo替换为animateTo:
_scrollController.animateTo( _previousScrollOffset, duration: Duration(milliseconds: 300), curve: Curves.easeInOut, );
内容的提问来源于stack exchange,提问作者Aaydin
相关产品推荐
相关产品推荐

