Flutter中使用CustomScrollView实现无限滚动的Provider调用问题
Flutter CustomScrollView 无限滚动实现方案
核心问题解决
1. onScroll 中调用 Provider 的方法
State 类本身自带全局可用的 context 成员,只要组件处于挂载(mounted == true)状态就可以直接使用,不需要额外传参。你之前注释的代码只需要补充挂载判断和加载锁即可正常运行。
2. 初始化加载的最佳实践
你当前用的 Timer.run 是为了等待组件初始化完成再获取上下文,更规范的实现是用 Flutter 官方提供的首帧回调API WidgetsBinding.instance.addPostFrameCallback,不需要依赖定时器。
优化后完整实现代码
class _FeedScreenState extends State<FeedScreen> { final _scrollController = ScrollController(); double _prevScrollPos = 0.0; // 加载锁,避免重复触发请求 bool _isLoadingMore = false; _onScroll() async { if (_isLoadingMore) return; // 加载中直接跳过 double maxScroll = _scrollController.position.maxScrollExtent; double currentScrollPos = _scrollController.position.pixels; double delta = 200.0; if (maxScroll - currentScrollPos <= delta && _prevScrollPos - currentScrollPos < 0 && mounted) { _isLoadingMore = true; // 直接使用State自带的context调用provider await Provider.of<GlobalFeeds>(context, listen: false).addPost(); _isLoadingMore = false; } _prevScrollPos = currentScrollPos; } @override void initState() { super.initState(); _scrollController.addListener(_onScroll); // 官方推荐的首帧完成后执行初始化加载 WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) { Provider.of<GlobalFeeds>(context, listen: false).addPost(); } }); } @override void dispose() { _scrollController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final globalFeeds = Provider.of<GlobalFeeds>(context); final posts = globalFeeds.posts; return Scaffold( body: CustomScrollView( controller: _scrollController, slivers: [ SliverAppBar( // 原有实现保留 ), SliverList( delegate: SliverChildBuilderDelegate((context, index) { // 可选:底部加加载中指示器 if (index == posts.length) { return _isLoadingMore ? const Padding(padding: EdgeInsets.all(16), child: CircularProgressIndicator()) : const SizedBox.shrink(); } final Post post = posts[index]; return PostContainer(post: post); }, childCount: posts.length + 1, // 多一个位置放加载指示器 ), ), ], ) ); } }
额外优化建议
- 可以把加载状态
isLoadingMore放到GlobalFeedsprovider 中管理,跨组件共享加载状态更方便 - 增加是否还有更多数据的判断(比如后端返回空列表时标记
hasMore = false),没有更多数据时直接停掉滚动监听,避免无意义的判断 - 请求失败时重置
_isLoadingMore标记,避免后续无法触发加载
内容的提问来源于stack exchange,提问作者Jérémie Chazelle
相关产品推荐
相关产品推荐

