Flutter滚动加载更多时未按预期加载5个产品的问题及解决方法
滚动加载更多时未按预期加载5个产品的问题排查与修复
问题描述
以下是实现滚动加载的Flutter代码,期望滚动到底部时每次加载5个产品,但实际触发加载时会加载更多数量:
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class Scroool extends StatefulWidget { const Scroool({Key? key}) : super(key: key); @override State<Scroool> createState() => _ScrooolState(); } class _ScrooolState extends State<Scroool> { List posts = []; int limit = 20; bool isLoadingMore = false; ScrollController controller = ScrollController(); @override void initState() { fetchPosts(); controller.addListener(scrolListener); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey.shade300, body: ListView.builder( controller: controller, padding: EdgeInsets.all(20), itemCount: isLoadingMore ? posts.length + 1 : posts.length, itemBuilder: (context, index) { if(index < posts.length) { final post = posts[index]; return Card( child: ListTile( leading: CircleAvatar(child: Text("${index + 1}"),), title: Text(post['title'].toString()), subtitle: Text(post['description']), ), ); } else { return Center(child: CircularProgressIndicator(),); } }, ), ); } fetchPosts() async { final url = Uri.parse("https://dummyjson.com/products?limit=$limit"); final response = await http.get(url); if(response.statusCode == 200) { final json = jsonDecode(response.body)['products'] as List; setState(() { posts = posts + json; isLoadingMore = false; }); } else { print("ERROR"); } } scrolListener() async{ //don' call the api if user scroll whil calling the api not finished yet if(isLoadingMore) return; if(controller.position.pixels == controller.position.maxScrollExtent) { setState(() { isLoadingMore = true; }); limit+=5; await fetchPosts(); setState(() { isLoadingMore = false; }); } else { print("not called"); } } }
问题:当滚动到列表底部触发加载更多时,并未按照代码中设定的加载5个产品,而是加载了更多数量。
原因分析
当前逻辑的核心问题是API请求参数和数据叠加方式错误:
- 每次触发加载时,你把
limit增加5(比如从20→25→30...),然后请求limit数量的产品 - 接着把返回的所有数据(25个、30个...)直接追加到原有列表,导致每次加载的是
limit总数的产品,而非新增5个 - 例如第一次加载20个,第二次请求25个并追加,最终列表变成20+25=45个,相当于多加载了25个而非预期的5个
修复方案
改用skip参数跳过已加载的产品,每次固定请求5个新数据:
- 新增
skip变量记录已加载的产品数量,初始值为0 - 初始请求时加载20个,之后每次加载时
skip累加5,固定limit=5请求新数据 - 调整数据处理逻辑,确保只追加新增的5个产品
修改后的完整代码
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class Scroool extends StatefulWidget { const Scroool({Key? key}) : super(key: key); @override State<Scroool> createState() => _ScrooolState(); } class _ScrooolState extends State<Scroool> { List posts = []; final int initialLimit = 20; final int loadMoreLimit = 5; int skip = 0; bool isLoadingMore = false; ScrollController controller = ScrollController(); @override void initState() { fetchPosts(isInitialLoad: true); controller.addListener(scrolListener); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey.shade300, body: ListView.builder( controller: controller, padding: EdgeInsets.all(20), itemCount: isLoadingMore ? posts.length + 1 : posts.length, itemBuilder: (context, index) { if (index < posts.length) { final post = posts[index]; return Card( child: ListTile( leading: CircleAvatar(child: Text("${index + 1}")), title: Text(post['title'].toString()), subtitle: Text(post['description']), ), ); } else { return const Center(child: CircularProgressIndicator()); } }, ), ); } fetchPosts({bool isInitialLoad = false}) async { int currentLimit = isInitialLoad ? initialLimit : loadMoreLimit; final url = Uri.parse("https://dummyjson.com/products?limit=$currentLimit&skip=$skip"); final response = await http.get(url); if (response.statusCode == 200) { final json = jsonDecode(response.body)['products'] as List; setState(() { posts.addAll(json); isLoadingMore = false; // 更新skip,下次请求跳过已加载的数量 skip += json.length; }); } else { print("ERROR"); setState(() { isLoadingMore = false; }); } } scrolListener() async { if (isLoadingMore) return; if (controller.position.pixels == controller.position.maxScrollExtent) { setState(() { isLoadingMore = true; }); await fetchPosts(); } else { print("not called"); } } }
关键修改点
- 新增
initialLimit(初始加载20个)和loadMoreLimit(每次加载5个)常量,明确区分初始和加载更多的数量 - 新增
skip变量,每次请求后累加已加载的产品数量,确保下次请求跳过已有的数据 - 修改
fetchPosts方法,根据是否是初始加载选择对应的limit,并带上skip参数 - 使用
posts.addAll(json)替代posts = posts + json,写法更简洁高效 - 加载失败时也重置
isLoadingMore,避免加载状态卡死
内容的提问来源于stack exchange,提问作者Osama Mohammed
相关产品推荐
相关产品推荐

