I have a list where I want to display a list of objects. Each object has a json field where "tags" are defined. Each consists of a field name and a value. The values from the fields contained in json have to be displayed in a nice looking form of "tiles". When a field is focused, the field name (ToolTip) should appears.
I wrote my widget that converts json for this. Works fine, but I've found that performance of list slows down much with number of items (scrolling and hovering over an item) At 10 it is still ok, but at 50 it's not. When I comment "JsonWidget" and just use Text widget, everything works fast. I wonder if there is a way to write it in a more optimal way.
Her is full code:
import 'dart:convert';
import 'package:flutter/material.dart';
void main() {
runApp(GenistryApp());
}
//My example object with json field
class MyObject {
int id;
String json =
'{"year":1850,"1 name":"Zuzanna","names":"Stefania","surname":"Zabłocka","sex":"W","city":"Warsaw","date":"1850.01.02","father":"Piotr","mothers_anme":"Józefa","mothers_surname":"Wojnicz","info":"Szlachetni"}';
MyObject(this.id);
}
class GenistryApp extends StatelessWidget {
const GenistryApp({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyTableWidget(),
theme: ThemeData(
primarySwatch: Colors.lightGreen,
visualDensity: VisualDensity.adaptivePlatformDensity,
));
}
}
class MyTableWidget extends StatefulWidget {
const MyTableWidget({Key key}) : super(key: key);
@override
_MyTableWidgetState createState() => _MyTableWidgetState();
}
class _MyTableWidgetState extends State<MyTableWidget> {
MyDataTableSource _data = MyDataTableSource([]);
List<MyObject> list = [];
//Generating 50 same elements for testing
getData() {
for (int i = 0; i < 50; i ) {
list.add(MyObject(i));
}
_data = MyDataTableSource(list);
}
@override
Widget build(BuildContext context) {
getData();
return Scaffold(
backgroundColor: Colors.white.withOpacity(0.8),
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: PaginatedDataTable(
source: _data,
columns: [
DataColumn(label: Container()),
DataColumn(
label: ConstrainedBox(
constraints: BoxConstraints.expand(
width: MediaQuery.of(context).size.width))),
],
columnSpacing: 50,
horizontalMargin: 10,
rowsPerPage: 50,
showCheckboxColumn: false,
),
));
}
}
class MyDataTableSource extends DataTableSource {
List<MyObject> _data;
MyDataTableSource(this._data);
bool get isRowCountApproximate => false;
int get rowCount => _data.length;
int get selectedRowCount => 0;
DataRow getRow(int index) {
return DataRow(cells: [
DataCell(Text("ID")),
DataCell(
JsonWidget(_data[index]
.json), // Here is my widget to convert json field - it slows all list
// Text(_data[index].json), // Here is simple json field for testing - it works fast
onTap: () => {},
),
]);
}
}
//Widget to convert json to nice looking "tags"
class JsonWidget extends StatelessWidget {
String jdata;
Map<String, dynamic> data;
JsonWidget(String jdata) {
this.jdata = jdata;
}
var containers = <Tooltip>[];
@override
Widget build(BuildContext context) {
this.data = json.decode(this.jdata);
data.entries.forEach((element) {
containers.add(new Tooltip(
message: element.key, //tag's fieldname
textStyle: TextStyle(color: Colors.white),
child: Container(
margin: const EdgeInsets.all(3),
padding: const EdgeInsets.all(4),
child: Text(element.value.toString()), //tag's fieldvalue
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent, width: 0.7),
borderRadius: BorderRadius.all(Radius.circular(20))),
)));
});
return Row(children: this.containers);
}
}
CodePudding user response:
The build method is designed in such a way that it should be pure/without side effects. It should only return a widget and not run for loops as in the JsonWidget case. A better way to write this will be
class JsonWidget extends StatelessWidget {
Map<String, dynamic> data;
JsonWidget(Map<String, dynamic> data) {
this.data = data;
}
var containers = <Tooltip>[];
@override
Widget build(BuildContext context) {
return Row(children: [
for (var element in data.entries)
Tooltip(
message: element.key, //tag's fieldname
textStyle: TextStyle(color: Colors.white),
child: Container(
margin: const EdgeInsets.all(3),
padding: const EdgeInsets.all(4),
child: Text(element.value.toString()), //tag's fieldvalue
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent, width: 0.7),
borderRadius: BorderRadius.all(Radius.circular(20))),
))
]);
}
}
And MyDataTableSoure will look like this
class MyDataTableSource extends DataTableSource {
List<MyObject> _data;
MyDataTableSource(this._data);
bool get isRowCountApproximate => false;
int get rowCount => _data.length;
int get selectedRowCount => 0;
DataRow getRow(int index) {
return DataRow(cells: [
DataCell(Text("ID")),
DataCell(
JsonWidget(json.decode(_data[index]
.json)), // Here is my widget to convert json field - it slows all list
// Text(_data[index].json), // Here is simple json field for testing - it works fast
onTap: () => {},
),
]);
}
}