我的项目中有这个“屏幕”:
import 'dart:convert';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:medlabo_desktop/models/search_result.dart';
import 'package:medlabo_desktop/models/test/test.dart';
import 'package:medlabo_desktop/models/test/test_request.dart';
import 'package:medlabo_desktop/models/test_parametar/test_parametar.dart';
import 'package:medlabo_desktop/models/test_parametar/test_parametar_request.dart';
import 'package:medlabo_desktop/providers/test_parametri_provider.dart';
import 'package:medlabo_desktop/providers/testovi_and_test_parametri_provider.dart';
import 'package:medlabo_desktop/providers/testovi_provider.dart';
import 'package:medlabo_desktop/utils/constants/design.dart';
import 'package:medlabo_desktop/utils/constants/nums.dart';
import 'package:medlabo_desktop/utils/general/dialog_utils.dart';
import 'package:medlabo_desktop/utils/general/toast_utils.dart';
import 'package:medlabo_desktop/utils/general/util.dart';
import 'package:provider/provider.dart';
class TestoviDataTableSource extends DataTableSource {
final TestoviProvider _provider;
final BuildContext context;
List<Test> _data = [];
int _totalDataCount = 0;
TestoviDataTableSource(this._provider, this.context);
Future fetchData(int page) async {
var filter = {'Page': page - 1, 'PageSize': 2};
var result = await _provider.get(filter: filter);
_data = result.result;
_totalDataCount = result.count;
notifyListeners();
}
//zašto neće da vrati index na 0 kad se prebaci strana?
@override
DataRow getRow(int index) {
if (index >= _data.length) {
return DataRow(
cells: List.generate(
6, (index) => DataCell(CircularProgressIndicator())));
}
final test = _data[index];
return DataRow(cells: [
DataCell(
Container(
width: 100.0,
child: GestureDetector(
onTap: () {
(test.naziv?.length ?? 0) > 12
? showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text(test.naziv ?? 'Nema naziv'),
);
},
)
: null;
},
child: Text(
test.naziv ?? 'Nema naziv',
overflow: TextOverflow.ellipsis,
),
),
),
),
DataCell(
Container(
width: 150.0,
child: GestureDetector(
onTap: () {
(test.opis?.length ?? 0) > 20
? showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text(test.opis ?? 'Nema opis'),
);
},
)
: null;
},
child: Text(
test.opis ?? 'Nema opis',
overflow: TextOverflow.ellipsis,
),
),
),
),
DataCell(Text(
formatNumberToPrice(test.cijena),
overflow: TextOverflow.fade,
)),
DataCell(
Container(
width: 150.0,
child: GestureDetector(
onTap: () {
(test.napomenaZaPripremu?.length ?? 0) > 20
? showDialog(
context: context,
builder: (context) {
return AlertDialog(
content:
Text(test.napomenaZaPripremu ?? 'Nema napomenu'),
);
},
)
: null;
},
child: Text(
test.napomenaZaPripremu ?? 'Nema napomenu',
overflow: TextOverflow.ellipsis,
),
),
),
),
DataCell(Text(
test.dtKreiranja == null
? 'Nepoznat'
: formatDateTime(test.dtKreiranja!) ?? 'Nepoznat',
overflow: TextOverflow.fade,
)),
DataCell(
//_buildOptionsForTest(context, test),
Text('opcije'),
),
]);
}
@override
bool get isRowCountApproximate => false;
@override
int get rowCount => _totalDataCount;
@override
int get selectedRowCount => 0;
}
class TestoviScreen extends StatefulWidget {
const TestoviScreen({super.key});
@override
State<TestoviScreen> createState() => _TestoviScreenState();
}
class _TestoviScreenState extends State<TestoviScreen> {
late TestoviProvider _testoviProvider;
late TestParametriProvider _testParametriProvider;
late TestoviAndTestParametriProvider _testoviAndTestParametriProvider;
SearchResult<Test>? testovi;
TextEditingController _testSearchController = new TextEditingController();
final _formKey = GlobalKey<FormBuilderState>();
late TestoviDataTableSource _dataSource;
@override
void initState() {
super.initState();
_testoviProvider = context.read<TestoviProvider>();
_dataSource = TestoviDataTableSource(_testoviProvider, context);
_dataSource.fetchData(1);
initForm();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_testParametriProvider = context.read<TestParametriProvider>();
_testoviAndTestParametriProvider =
context.read<TestoviAndTestParametriProvider>();
}
bool _isDataLoaded = false;
Future initForm() async {
var data = await _testoviProvider.get();
if (mounted) {
setState(() {
testovi = data;
_isDataLoaded = true;
});
}
}
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Container(
width: double.infinity,
height: double.infinity,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(6),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 1,
blurRadius: 7,
offset: const Offset(0, 3),
),
],
),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(15, 10, 15, 0),
child: _buildTestoviHeader(),
),
Padding(
padding: const EdgeInsets.all(10),
child: _buildTestoviDataTable(context),
),
],
),
),
),
);
}
Row _buildTestoviDataTable(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: _isDataLoaded == true
? PaginatedDataTable(
rowsPerPage: 2,
onPageChanged: (int page) async {
await _dataSource.fetchData(page);
},
columns: const [
DataColumn(
label: Tooltip(
message: 'Ime testa',
child: Text(
'Naziv',
overflow: TextOverflow.ellipsis,
),
)),
DataColumn(
label: Tooltip(
message: 'Kratak opis testa',
child: Text(
'Opis',
overflow: TextOverflow.ellipsis,
),
)),
DataColumn(
label: Tooltip(
message: 'Cijena jednog testa',
child: Text(
'Cijena',
overflow: TextOverflow.ellipsis,
),
)),
DataColumn(
label: Tooltip(
message:
'Upute koje se trebaju slijediti prije dolaska na test',
child: Text(
'Napomena za pripremu',
overflow: TextOverflow.ellipsis,
),
)),
DataColumn(
label: Tooltip(
message: 'Datum kada je kreiran test',
child: Text(
'Datum kreiranja',
overflow: TextOverflow.ellipsis,
),
)),
DataColumn(label: Text('Opcije')),
],
source: _dataSource,
)
: const FittedBox(
fit: BoxFit.scaleDown,
child: SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator()),
),
),
],
);
}//and another code
现在,正如大家所看到的,我正在尝试使用 PagulatedDataTable 进行服务器端分页,因为我的后端具有分页逻辑,因此通过 get 请求,我可以获取特定页面的记录和所有记录的计数。当我打开屏幕时,我得到PaginatedDataTable,并且我得到第一页就好了,但是当我更改到第二页时,我没有得到错误,但其列具有无限加载的循环加载器的行,然后当我返回第一页时,我得到错误:“在 882 毫秒内重新加载了 1225 个库中的 3 个(编译:385 毫秒,重新加载:203 毫秒,重新汇编:198 毫秒)。 [错误:flutter/runtime/dart_vm_initializer.cc(41)] 未处理的异常:异常:获取请求失败 #0 BaseProvider.get(包:medlabo_desktop/providers/base_provider.dart:49:5) #1 TestoviDataTableSource.fetchData(包:medlabo_desktop/screens/administrator/testovi_screen.dart:34:18) #2 _TestoviScreenState._buildTestoviDataTable。 (包:medlabo_desktop/screens/administrator/testovi_screen.dart:239:21) “。我在调试时看到的奇怪行为是,当我切换到第二页时,它会进入方法 fetchData 并进入
var result = await _provider.get(filter: filter);
行,之后它不会继续在该函数中执行操作,而是转到 getRow 函数重写立即,该函数中的内容执行。为什么会发生这种情况?
我尝试了一切:'(
PaginatedDataTable 不支持异步获取数据,请检查:https://github.com/flutter/flutter/issues/87348
您可以尝试使用此插件:https://pub.dev/packages/data_table_2
还有讨论中提到的其他插件:https://pub.dev/packages/advanced_datatable
无论如何,我也必须处理这个问题,最终我使用了常规的 DataTable 并自己进行了分页。