Flutter PaginatedDataTable切换分页仅加载无数据问题求助
问题排查与修复方案
核心问题分析
你的代码存在几个关键问题导致切换分页后无法展示数据:
- API请求未使用传入的页码参数:
fetchDataFromApi方法接收了pageIndex参数,但实际拼接URL时误用了类内部的_pageIndex变量,导致切换页面时请求的页码始终不变。 - 总行数计算逻辑错误:
rowCount使用位运算_data.length | _rowCount,这会导致数值异常,PaginatedDataTable无法正确计算总页数和分页状态。 - 分页参数未同步:数据源内部的
_rowsPerPage、_pageIndex未与外部组件的状态同步,导致分页参数不一致。 - 页码索引混乱:外部组件页码从0开始,内部从1开始,切换页面时的加1操作进一步加剧了参数混乱。
修复后的完整代码
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:mobile_ess/helpers/url_helper.dart'; import 'package:shared_preferences/shared_preferences.dart'; class PicHrgs extends StatefulWidget { const PicHrgs({super.key}); @override State<PicHrgs> createState() => _PicHrgsState(); } class _PicHrgsState extends State<PicHrgs> { final MyDataSource dataSource = MyDataSource(); late int _rowsPerPage = PaginatedDataTable.defaultRowsPerPage; // 统一使用从1开始的页码,和API保持一致 late int _currentPage = 1; @override Widget build(BuildContext context) { return SingleChildScrollView( child: PaginatedDataTable( columns: const <DataColumn>[ DataColumn(label: Text('NRP')), DataColumn(label: Text('Nama')), ], source: dataSource, rowsPerPage: _rowsPerPage, onRowsPerPageChanged: (value) { setState(() { _rowsPerPage = value!; // 切换每页条数后回到第一页 _currentPage = 1; dataSource.fetchDataFromApi(pageIndex: _currentPage, rowsPerPage: _rowsPerPage); }); }, onPageChanged: (pageIndex) { setState(() { // PaginatedDataTable的pageIndex从0开始,转换为API需要的从1开始的页码 _currentPage = pageIndex + 1; dataSource.fetchDataFromApi(pageIndex: _currentPage, rowsPerPage: _rowsPerPage); }); }, availableRowsPerPage: const [5, 10, 20, 100], ), ); } @override void initState() { super.initState(); dataSource.addListener(() { setState(() {}); }); dataSource.fetchDataFromApi(pageIndex: _currentPage, rowsPerPage: _rowsPerPage); } } class MyDataSource extends DataTableSource { List<List<Comparable<Object>>> _data = []; int _totalRecords = 0; bool _isLoading = false; final String apiUrl = API_URL; Future<void> fetchDataFromApi({required int pageIndex, required int rowsPerPage, String searchQuery = ''}) async { setStateLoading(true); SharedPreferences prefs = await SharedPreferences.getInstance(); String? token = prefs.getString('token'); try { final response = await http.get( Uri.parse("$apiUrl/master/hrgs/get?page=$pageIndex&perPage=$rowsPerPage&search=$searchQuery"), headers: <String, String>{ "Content-Type": "application/json;charset=UTF-8", 'Authorization': 'Bearer $token', }, ); if (response.statusCode == 200) { final Map<String, dynamic> responseData = json.decode(response.body); final List<dynamic> dataku = responseData['dataku']; final total = responseData["totalPage"]; _totalRecords = total['total_records'] ?? 0; _data = dataku.map<List<Comparable<Object>>>((data) { return [ data['nrp'] ?? '', data['nama'] ?? '', ]; }).toList(); } else { throw Exception('Failed to load data'); } } catch (e) { debugPrint(e.toString()); } finally { setStateLoading(false); notifyListeners(); } } void setStateLoading(bool loading) { _isLoading = loading; notifyListeners(); } @override DataRow? getRow(int index) { if (index >= 0 && index < _data.length) { return DataRow(cells: <DataCell>[ DataCell(Text(_data[index][0].toString())), DataCell(Text(_data[index][1].toString())), ]); } // 加载状态下显示加载单元格 if (_isLoading) { return DataRow(cells: List.generate(2, (index) => const DataCell(CircularProgressIndicator()))); } return null; } @override bool get isRowCountApproximate => false; @override int get rowCount => _isLoading ? _data.length + 1 : _totalRecords; @override int get selectedRowCount => 0; }
关键修复点说明
- 统一页码索引:外部组件将页码转换为API需要的从1开始的格式,避免索引混乱。
- 正确传递分页参数:
fetchDataFromApi方法接收rowsPerPage和pageIndex参数,并直接用于API请求,确保参数同步。 - 修复总行数逻辑:
rowCount根据加载状态返回对应数值,加载时显示额外的加载行,正常状态返回总记录数。 - 添加加载状态管理:新增
_isLoading状态,在请求过程中显示加载指示器,提升用户体验。 - 移除冗余状态:去掉数据源内部冗余的
_pageIndex和_rowsPerPage变量,直接使用外部传入的参数。
内容的提问来源于stack exchange,提问作者Mr. X
相关产品推荐
相关产品推荐

