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
相关产品推荐
相关产品推荐

