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

Flutter:下载完成后ListView索引重置问题的解决办法

解决方案

问题根源在于:当切换到CircularProgressIndicator时,原有的ListView组件会被完全销毁,下载完成重新构建ListView时,它会默认回到初始滚动位置(索引0)。我们可以通过ScrollController保存并恢复滚动位置,无需额外状态管理库,仅在当前State中处理即可。

具体实现步骤

  1. 在State类中定义ScrollController实例,以及用于保存滚动偏移量的变量
  2. 触发下载操作前,记录当前ListView的滚动位置
  3. 下载完成重新显示ListView后,通过控制器恢复之前的滚动位置
  4. 在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 03:28:11