You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 09:37:51