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

Flutter:如何在类间传递分页参数实现API数据懒加载

实现分页加载第三方API数据的方案

1. 改造DataTableSourceExample,支持分页参数接收与数据加载

先修改数据源类,让它能接收分页参数、触发API请求,并维护当前页数据和总条数:

class DataTableSourceExample extends DataTableSource {
  final int rowsPerPage;
  final int totalRows;
  final Future<void> Function(int startIndex, int rowsPerPage) fetchData;
  List<Map<String, dynamic>> _currentPageData = [];

  DataTableSourceExample({
    required this.rowsPerPage,
    required this.totalRows,
    required this.fetchData,
  });

  // 更新当前页数据并通知表格刷新
  void updateCurrentPageData(List<Map<String, dynamic>> data) {
    _currentPageData = data;
    notifyListeners();
  }

  @override
  DataRow? getRow(int index) {
    // 计算当前页内的相对索引
    final localIndex = index % rowsPerPage;
    // 索引超出已加载范围时返回空(可替换为加载占位)
    if (localIndex >= _currentPageData.length) return null;
    
    final item = _currentPageData[localIndex];
    return DataRow(cells: [
      DataCell(Text(item["id"].toString())),
      DataCell(Text(item["begin_datetime"].toString())),
      DataCell(Text(item["end_date"].toString())),
    ]);
  }

  @override
  bool get isRowCountApproximate => false; // API返回总条数准确时设为false

  @override
  int get rowCount => totalRows;

  @override
  int get selectedRowCount => 0;
}

2. 修改PaginatedDataTableExample,传递分页参数并处理分页事件

在页面状态类中维护分页状态,把参数传给数据源,同时处理页码切换、每页条数变更的事件:

class PaginatedDataTableExample extends StatefulWidget {
  const PaginatedDataTableExample({super.key});

  @override
  _PaginatedDataTableExampleState createState() =>
      _PaginatedDataTableExampleState();
}

class _PaginatedDataTableExampleState extends State<PaginatedDataTableExample> {
  int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage;
  int _currentStartIndex = 0;
  int _totalRows = 0; // 从API获取的总数据条数
  late DataTableSourceExample _dataSource;

  @override
  void initState() {
    super.initState();
    // 初始化数据源,传入分页参数和数据加载回调
    _dataSource = DataTableSourceExample(
      rowsPerPage: _rowsPerPage,
      totalRows: _totalRows,
      fetchData: _fetchPageData,
    );
    // 加载初始数据
    _fetchPageData(_currentStartIndex, _rowsPerPage);
  }

  // 调用第三方API加载指定页的数据
  Future<void> _fetchPageData(int startIndex, int rowsPerPage) async {
    // 替换为实际API请求逻辑,示例:
    // final response = await apiClient.getItems(start: startIndex, limit: rowsPerPage);
    // 模拟API返回数据
    final mockData = List.generate(
      rowsPerPage,
      (index) => {
        "id": startIndex + index,
        "begin_datetime": DateTime.now().toString(),
        "end_date": DateTime.now().add(const Duration(days: 1)).toString(),
      },
    );
    // 模拟获取总条数(实际从API响应头或返回体中获取)
    setState(() => _totalRows = 999999);
    // 更新数据源的当前页数据
    _dataSource.updateCurrentPageData(mockData);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        child: PaginatedDataTable(
          rowsPerPage: _rowsPerPage,
          onRowsPerPageChanged: (newRowsPerPage) {
            if (newRowsPerPage == null) return;
            setState(() {
              _rowsPerPage = newRowsPerPage;
              _currentStartIndex = 0; // 切换每页条数后回到第一页
            });
            // 重新加载第一页数据并更新数据源配置
            _fetchPageData(_currentStartIndex, _rowsPerPage);
            _dataSource = DataTableSourceExample(
              rowsPerPage: _rowsPerPage,
              totalRows: _totalRows,
              fetchData: _fetchPageData,
            );
          },
          onPageChanged: (newStartIndex) {
            setState(() => _currentStartIndex = newStartIndex);
            // 加载新页面的数据
            _fetchPageData(newStartIndex, _rowsPerPage);
          },
          columns: const [
            DataColumn(
              label: Text(
                "id",
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
            DataColumn(
              label: Text(
                "Begin",
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
            DataColumn(
              label: Text(
                "End",
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
            ),
          ],
          source: _dataSource,
        ),
      ),
    );
  }
}

核心逻辑说明

  • 参数传递:通过DataTableSourceExample的构造函数传入rowsPerPage和数据加载回调fetchData;起始索引在onPageChanged触发时,作为参数传给fetchData函数。
  • 分页加载:切换页面时,onPageChanged返回新页面的起始索引,调用_fetchPageData获取对应页数据;修改每页条数时,重置起始索引为0并重新加载第一页。
  • 数据更新:API返回数据后,调用_dataSource.updateCurrentPageData更新当前页数据,通过notifyListeners()通知表格刷新UI。

内容的提问来源于stack exchange,提问作者Joe Black

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 12:44:52