如何在Flutter中基于API实现产品列表分页功能
Flutter 产品列表分页实现方案
1. 修改API请求方法,支持动态页码参数
先把固定的page=1改成可传入的参数,同时封装分页元数据(比如总页数),方便后续判断分页边界:
// 封装分页返回结果,同时包含产品列表和分页信息 class ProductPageResult { final List<Product> products; final int totalPages; final int currentPage; ProductPageResult({ required this.products, required this.totalPages, required this.currentPage, }); } Future<ProductPageResult> getProductPage({required String token, required int page}) async { final response = await http.get( Uri.parse('$path/products?per_page=7&page=$page'), headers: header(token: token), ); if (response.statusCode == 200) { final jsonResponse = jsonDecode(response.body); final data = jsonResponse['data']; final productList = (data['data'] as List) .map((item) => Product.fromJson(item)) .toList(); return ProductPageResult( products: productList, totalPages: data['last_page'], // 请根据API实际返回的总页数字段调整 currentPage: data['current_page'], ); } else { throw Exception('加载产品列表失败'); } }
2. 页面状态与UI实现
在产品列表页面的State类中维护分页状态,实现页码切换逻辑:
class ProductListPage extends StatefulWidget { final String token; const ProductListPage({super.key, required this.token}); @override State<ProductListPage> createState() => _ProductListPageState(); } class _ProductListPageState extends State<ProductListPage> { List<Product> _products = []; int _currentPage = 1; int _totalPages = 1; bool _isLoading = false; @override void initState() { super.initState(); _loadProductPage(_currentPage); } Future<void> _loadProductPage(int page) async { setState(() => _isLoading = true); try { final result = await getProductPage(token: widget.token, page: page); setState(() { _currentPage = page; _products = result.products; _totalPages = result.totalPages; }); } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('加载失败: ${e.toString()}')), ); } } finally { if (mounted) setState(() => _isLoading = false); } } void _onPageTap(int newPage) { if (newPage < 1 || newPage > _totalPages || newPage == _currentPage) return; _loadProductPage(newPage); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('产品列表')), body: _isLoading ? const Center(child: CircularProgressIndicator()) : Column( children: [ // 产品列表区域 Expanded( child: ListView.builder( itemCount: _products.length, itemBuilder: (context, index) { final product = _products[index]; // 替换为你的产品列表项UI return ListTile(title: Text(product.name)); }, ), ), // 页码导航栏 Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate(_totalPages, (index) { final pageNum = index + 1; return Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: ElevatedButton( onPressed: () => _onPageTap(pageNum), style: ElevatedButton.styleFrom( backgroundColor: pageNum == _currentPage ? Colors.blue : Colors.grey.shade200, ), child: Text('$pageNum'), ), ); }), ), ), ], ), ); } }
3. 核心注意点
- 利用API返回的总页数字段(示例中为
last_page)限制页码范围,避免无效请求 - 切换页码时显示loading状态,优化用户体验
- 加入
mounted判断,防止异步请求完成后页面已销毁导致的报错 - 捕获请求异常并给出提示,避免页面崩溃
内容的提问来源于stack exchange,提问作者maliha arash
相关产品推荐
相关产品推荐

