Flutter Infinite Scroll Pagination自动加载下一页而非滚动触发问题
问题
使用infinite_scroll_pagination包构建PagedGridView时,预期首次加载9个颜色块网格项,用户滚动到页面底部时再触发分页监听器请求更多数据(直到达到总数据量)。但当前无需触发滚动行为,PagedGridView就会自动按pageSize(9)增量加载所有数据,这会导致后续对接数据库时产生不必要的读取操作。
当前布局是将PagedGridView<int, Color>作为ListView的子组件,并用RefreshIndicator包裹页面主体以支持手动刷新。
解决方案
问题根源
PagedGridView设置了shrinkWrap: true和physics: NeverScrollableScrollPhysics(),导致它失去自身滚动感知能力,外层ListView会一次性渲染所有内容,触发分页控制器持续加载数据。- 分页逻辑中的终止条件判断不准确,
pageKey > _colors.length无法正确识别是否已加载完所有数据。
修改步骤
- 调整布局结构:移除
PagedGridView的shrinkWrap和physics配置,将外层ListView替换为CustomScrollView,把顶部Card转为SliverToBoxAdapter组件,与PagedGridView的sliver版本结合,既保留顶部固定内容,又让网格正常监听滚动。 - 修正分页终止逻辑:调整
_fetchPage中的判断条件,确保当起始加载位置超过总数据长度时,直接标记为最后一页。
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; class InfiniteScroll extends StatefulWidget { const InfiniteScroll({super.key}); @override State<InfiniteScroll> createState() => _InfiniteScrollState(); } class _InfiniteScrollState extends State<InfiniteScroll> { final List<Color> _colors = List.generate( 100, (index) => Color(index * 0xFFFFFF ~/ 1000).withOpacity(0.5), ); static const int _pageSize = 9; final PagingController<int, Color> _pagingController = PagingController(firstPageKey: 0); @override void initState() { _pagingController.addPageRequestListener(_fetchPage); super.initState(); } Future<void> _fetchPage(int pageKey) async { try { // 修正终止条件:当前起始位置已超过总数据量,直接返回空的最后一页 if (pageKey >= _colors.length) { _pagingController.appendLastPage([]); return; } final newItems = await Future.wait(List.generate(_pageSize, (index) => Future.delayed(const Duration(milliseconds: 50)))) .then((_) => _colors.skip(pageKey).take(_pageSize).toList()); final isLastPage = pageKey + newItems.length >= _colors.length; if (isLastPage) { _pagingController.appendLastPage(newItems); } else { final nextPageKey = pageKey + newItems.length; _pagingController.appendPage(newItems, nextPageKey); } } catch (e) { _pagingController.error = e; debugPrint(e.toString()); } } @override Widget build(BuildContext context) { return Scaffold( body: RefreshIndicator( onRefresh: () async => _pagingController.refresh(), // 替换为CustomScrollView,结合sliver组件实现混合布局 child: CustomScrollView( slivers: [ SliverToBoxAdapter( child: Card( child: ListTile( title: const Text("Infinite Scroll Pagination"), subtitle: const Text("Infinite Scroll Pagination"), trailing: const Icon(Icons.arrow_forward_ios), ), ), ), // 使用PagedGridView的sliver版本,配合CustomScrollView工作 PagedSliverGridView<int, Color>( pagingController: _pagingController, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, mainAxisSpacing: 4.0, crossAxisSpacing: 4.0, ), builderDelegate: PagedChildBuilderDelegate<Color>( itemBuilder: (context, item, index) { return Container( color: item, child: InkWell( onTap: () { debugPrint("Color: $item"); }, child: Center( child: Text( index.toString(), style: const TextStyle(fontSize: 20), ), ), ), ); }, ), ), ], ), ), ); } @override void dispose() { _pagingController.dispose(); super.dispose(); } }
说明
- 使用
PagedSliverGridView替代PagedGridView,配合CustomScrollView实现顶部固定内容+滚动网格的混合布局。 - 修正后的
_fetchPage逻辑会准确判断是否已加载完所有数据,避免不必要的请求触发。 - 移除了
NeverScrollableScrollPhysics,让网格自身处理滚动事件,只有当用户滚动到底部时才会触发下一页数据加载。
内容的提问来源于stack exchange,提问作者Spencer
相关产品推荐
相关产品推荐

