Flutter中ListView Builder无法正常渲染无限滚动数据问题求助
Flutter Provider无限滚动分页不实时渲染问题修复
问题
使用Provider做状态管理实现无限滚动分页时,出现以下异常:
- 应用启动后,API成功加载数据,但ListView不会立即展示内容,需切换到其他页面再返回才显示
- 滚动到底部加载更多数据后,新数据同样需要切换页面才能渲染
核心原因
- 页面未监听Provider状态变化:HomePage在
initState中获取Provider实例后,直接在build里使用该实例,没有通过Consumer或带listen: true的Provider.of监听状态更新,导致Provider调用notifyListeners()时页面不会重建。 - Provider状态更新逻辑不严谨:
loadMoreData中开始加载时未通知状态,加载完成后的通知逻辑存在遗漏场景refreshData中直接调用listOfUserData.clear()未触发通知,且方法标记为async却无异步操作
- ListView的itemCount计算错误:未考虑加载更多时的加载提示项,导致无法显示加载状态
修复代码
1. 修改HomePage,添加状态监听
用Consumer包裹ListView,确保状态更新时页面自动重建:
import 'package:end_point/providers/user_info_provider.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class HomePage extends StatefulWidget { const HomePage({super.key}); @override State<HomePage> createState() => _HomePageState(); } class _HomePageState extends State<HomePage> { final _scrollController = ScrollController(); late UserInfoProvider userInfoProvider; @override void initState() { super.initState(); userInfoProvider = Provider.of<UserInfoProvider>(context, listen: false); WidgetsBinding.instance.addPostFrameCallback((_) { userInfoProvider.loadMoreData(); }); _scrollController.addListener(_onScroll); } Future<void> _onScroll() async { if (_scrollController.position.pixels >= _scrollController.position.maxScrollExtent * 0.9 && !userInfoProvider.isLoading && userInfoProvider.hasMore) { await userInfoProvider.loadMoreData(); } } @override void dispose() { _scrollController.dispose(); super.dispose(); } Future refresh() async { userInfoProvider.refreshData(); await userInfoProvider.loadMoreData(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("END POINT LEGGO")), body: Consumer<UserInfoProvider>( builder: (context, provider, child) { return RefreshIndicator( key: UniqueKey(), onRefresh: refresh, child: ListView.builder( key: const PageStorageKey<String>('HP'), itemCount: provider.listOfUserData.length + (provider.hasMore && !provider.isLoading ? 1 : 0), controller: _scrollController, shrinkWrap: true, itemBuilder: (context, index) { if (index < provider.listOfUserData.length) { final id = provider.listOfUserData[index].id; return Padding( padding: const EdgeInsets.all(2.0), child: Container( height: 50, width: 200, decoration: const BoxDecoration( borderRadius: BorderRadius.all(Radius.circular(20)), color: Colors.red, ), child: ListTile(title: Text('$id')), ), ); } else { return Padding( padding: const EdgeInsets.symmetric(vertical: 32), child: Center( child: provider.isLoading ? const CircularProgressIndicator() : const Text('No more data to load'), ), ); } }, ), ); }, ), ); } }
2. 修正UserInfoProvider的状态更新逻辑
import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:end_point/models/UserInfo.dart'; import 'package:end_point/api/user_info_api.dart' as UserInfoAPI; import 'package:end_point/models/API/user_info_response.dart'; class UserInfoProvider with ChangeNotifier { int _page = 1; int get page => _page; bool _isLoading = false; bool get isLoading => _isLoading; List<UserInfo> _listOfUserData = []; List<UserInfo> get listOfUserData => _listOfUserData; set listOfUserData(List<UserInfo> listOfUserData) { _listOfUserData = listOfUserData; notifyListeners(); } bool _hasMore = true; bool get hasMore => _hasMore; Future<void> loadMoreData() async { if (_isLoading || !_hasMore) return; _isLoading = true; notifyListeners(); // 通知开始加载 try { ListOfUserInfoResponse response = await UserInfoAPI.getListOfUserInfo(_page); _listOfUserData.addAll(response.listOfUserInfo); _page++; // API的_limit是15,所以判断长度小于15时表示没有更多数据 if (response.listOfUserInfo.length < 15) { _hasMore = false; } } catch (e) { debugPrint('加载失败: $e'); } finally { _isLoading = false; notifyListeners(); // 通知加载完成 } } void refreshData() { _isLoading = false; _hasMore = true; _page = 1; _listOfUserData.clear(); notifyListeners(); // 手动通知列表清空 } }
关键修复点说明
- 添加状态监听:通过
Consumer让HomePage感知Provider的状态变化,确保数据更新时自动刷新UI - 完善状态通知:在
loadMoreData的加载开始、结束阶段都调用notifyListeners(),同时处理异常场景 - 修正itemCount:增加加载提示项的计数,让ListView能显示加载状态
- 优化滚动触发逻辑:提前90%位置触发加载,提升用户体验
内容的提问来源于stack exchange,提问作者Lim Jiexian
相关产品推荐
相关产品推荐

