I have a data table that scrolls horizontally and vertically due to the amount of data available. I want the top row which specifies the column names to always be visible when scrolling down.
code: No issues in the code I am getting the results, but when I scroll down The header wont be shown. Can any one help me in how to fix the header(1st row).
My header(1st row) elements keeps changing for each req,
the way its implemented is there will be cards in my dashboard onclicking each card it hits the API and I am displaying its result i.e contents of field named header list as my first row.
Content of the header keeps changing for each card. so once any card is clicked new page containing its data will popup, there I need to fix the header.
Widget getTable(BuildContext context, var data) {
Widget _widget;
_widget = SingleChildScrollView(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
rows: createDataRows(context, data),
columns: createDataColumns(context, data),
),
),
);
return _widget;
}
List<DataRow> createDataRows(BuildContext context, var jsonData) {
List<DataRow> _dataRows = [];
List<DataCell> _cells = [];
String _dataCellTitle;
Map<String, Object> headers = jsonData['headers'];
Map<int, String> headerMapping;
headerMapping = headers.keys
.toList()
.asMap()
.map((index, value) => MapEntry(index + 1, value));
if (jsonData["data"] == null) {
_dataRows = [];
} else {
for (var j = 0; j < jsonData["data"].length; j++) {
_cells.add(DataCell(Text('${j + 1}')));
for (int i = 1; i <= headerMapping.length; i++) {
_dataCellTitle = "${jsonData["data"][j][headerMapping[i]]}" ?? '-';
_cells.add(DataCell(Text('$_dataCellTitle')));
}
_dataRows.add(DataRow(cells: _cells));
_cells = [];
}
}
return _dataRows;
}
List<DataColumn> createDataColumns(BuildContext context, var jsonData) {
String columnTitle;
List<DataColumn> _dataColumns = [];
Map<String, Object> headers = jsonData['headers'];
Map<int, String> headerMapping;
headerMapping = headers.keys
.toList()
.asMap()
.map((index, value) => MapEntry(index + 1, value));
_dataColumns.add(DataColumn(label: Text('S. No.')));
for (int i = 1; i <= headerMapping.length; i++) {
columnTitle = headers[headerMapping[i]];
_dataColumns.add(
DataColumn(label: Text('$columnTitle')),
);
}
return _dataColumns;
}
like this here
where the first row is constant and first column also.
You can do the smart thing here, You can create two datatables one with only column, and one with rows.
Suppose your list_rows is a List<DataRow> and list_column is List<DataColumn> of your actual columns, then:
Column(
children: [
DataTable(
rows: [], // DONT PROVIDE ROWS
columns: list_column, // PROVIDE YOUR COLUMNS HERE
),
Expanded(
child: SingleChildScrollView(
child: DataTable(
rows: list_lows, // PROVIDE ROWS HERE
columns: List.generate(
list_column.length, (index) => DataColumn(label: Text(''))), // GENERATE EMPTY COLUMNS
headingRowHeight: 0, // SHRINK THE HEADER
),
),
),
],
)
This way your columns will always be on top!
Okay so you have one method getTable to get data content,
In it you are calling two methods
1) To fetch rows
2) To fetch columns.
But you didn't show the code of DataTable Widget.
I assume it is ListView or Column.
So in your DataTable Widget you should create one static Row for that heading.
ListView(
children: <Widget>[
Row(
children: <Widget>[
Text('$heading1'),
Text('$heading2'),
Text('$heading3'),
],
),
/// Your row and column
],
);
With information you provided i assume it will help you out.
I have Used Like that , and its working fine :
SingleChildScrollView dataBody() {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: DataTable(
columnSpacing: 10,
//sortAscending: sort,
//sortColumnIndex: 0,
columns: [
DataColumn(label: Text("Date"), numeric: false),
DataColumn(label: Text("Particulars"), numeric: false),
DataColumn(label: Text("Amount"), numeric: true)
],
rows: transactions
.map((txn) => DataRow(cells: [
DataCell(
Text(
DateFormat('dd-MMM-yyyy').format(txn.date),
style: TextStyle(fontSize: 12.0),
),
/*onTap: () {
print('Selected ${txn.date}');
}*/
),
DataCell(FittedBox(
child: Text(
txn.particulars,
),
)),
DataCell(Text(txn.amount.toString()))
]))
.toList(),
),
));
}
This is the solution to make Datatable Header sticky :
SizedBox(
height: 500,
width: 1000,
child: Scrollbar(
controller: _vertical,
thumbVisibility: true,
trackVisibility: true,
child: Scrollbar(
controller: _horizontal,
thumbVisibility: true,
trackVisibility: true,
child: SingleChildScrollView(
controller: _horizontal,
scrollDirection: Axis.horizontal,
child: Stack(
children: [
SingleChildScrollView(
controller: _vertical,
scrollDirection: Axis.vertical,
child: DataTable(
rows: list_rows, // PROVIDE ROWS HERE
columns: List.generate(
list_column.length,
(index) => DataColumn(
label: Text(''),
),
), //GENERATE EMPTY COLUMNS
headingRowHeight: 90, // HEADER HEIGHT
),
),
DataTable(
rows: [], // DONT PROVIDE ROWS
columns:
list_column, // PROVIDE YOUR COLUMNS HERE
headingRowHeight: 90, // HEADER HEIGHT
headingRowColor: MaterialStateColor.resolveWith(
(states) => Color.fromRGBO(86, 153, 255, 1),
),
border: TableBorder.all(
width: 1.0, color: Colors.white),
),
],
),
),
),
),
),
Related
I am working on a flutter where I have 2 Lists, 1. usersEmails, usersNames
How can I sort that code in a way that 1st element of userEmails and userNames become the 1st Row of data table.
Example:
List of Emails: [ABC, DEF, GHI]
List of Names: [MNO, PQR, XYZ]
What I want is:
The Data Rows will depend on the total numbers elements in the Email/Name List.
DataTable(
columns: const [
DataColumn(label: Text('ID'),),
DataColumn(label: Text('Email'),),
DataColumn(label: Text('Name'),),
],
rows: const [
DataRow(cells: [
DataCell(Text("101")),
DataCell(Text("ABC")),
DataCell(Text("MNO")),
]),
DataRow(cells: [
DataCell(Text("102")),
DataCell(Text("DEF")),
DataCell(Text("PQR")),
]),
DataRow(cells: [
DataCell(Text("103")),
DataCell(Text("GHI")),
DataCell(Text("XYZ")),
]),
]
)
Can you try following code.
class _MyHomePageState extends State<MyHomePage> {
List lst = ['ABC', 'DEF', 'GHI'];
List lst2 = ['asdas', 'adsasd', 'dfaas'];
List<DataRow> generateDataRow(List ls) {
List<DataRow> dataRows = [];
//Both list should have same length
//Otherwise it will throw errors.
for (int i=0; i<ls.length; i++) {
dataRows.add(
DataRow(
cells: [
DataCell(Text(ls[i])),
DataCell(Text(lst2[i])),
]
)
);
}
return dataRows;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16),
child: DataTable2(
columnSpacing: 12,
horizontalMargin: 12,
minWidth: 600,
columns: const [
DataColumn2(
label: Text('Email'),
size: ColumnSize.L,
),
DataColumn(
label: Text('Name'),
),
],
rows: generateDataRow(lst),),
),// This trailing comma makes auto-formatting nicer for build methods.
);
}
}
I am creating a DataTable and want to keep the automatically generated checkbox column that indicates which row is currently selected. My implementation only allows a single row to be selected at once, so I want to get rid of the automatically generated checkbox in the header row that causes all rows to be selected at once. I tried setting onSelectAll to null, but that did not hide the checkbox. Setting onSelectAll: (b) {} disables the functionality but does not hide the checkbox.
Here is the code for the function I'm using to generate the table:
Widget _itemTable(List data) {
if(data.length == 0) {
return Container(
margin: EdgeInsets.only(top: 20),
child: Text("No data found")
);
}
var headers = data[0].keys;
List<DataRow> rows = [];
int selectedIndex = 1;
int i = 0;
data.forEach(
(item) {
rows.add(
DataRow(
selected: selectedIndex == i,
onSelectChanged: (selected) {
if (selected ?? false) {
print(item);
selectedIndex = i;
}
},
cells:
headers.map<DataCell>(
(String hdr) => DataCell(Text(item[hdr].toString()))
).toList()
)
);
i++;
}
);
return Container(
margin: EdgeInsets.only(top: 10),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
onSelectAll: (b) {},
columns: ["id", "category", "subject", "details"].map<DataColumn>((h) => DataColumn(label: Text(h))).toList(),
rows: rows
)
)
);
}
The data List is just a list of objects with keys matching the headers listed in the columns of the DataTable
Lets say I want to randomly position the widgets in a specific layout, like in the image attached below, how could I achieve it?
I was thinking of using a wrap widget, but that did not quit work, because it is not randomizing the children in a line. My code until now
return Wrap(
spacing: 30,
children: [
buildprofile(),
buildprofile(),
buildprofile(),
buildprofile(),
],
);
buildprofile() {
return Column(
children: [
CircleAvatar(
radius: 64,
backgroundColor: Colors.pink,
child: (CircleAvatar(
radius: 62,
backgroundImage: NetworkImage(profilepic),
)),
),
SizedBox(
height: 10,
),
Text(
"Sivaram",
style: mystyle(16, Colors.black, FontWeight.w700),
)
],
);
}
You could use flutter_staggered_grid_view
StaggeredGridView.count(
crossAxisCount: 4,
children: List.generate(
3,
(index) => Center(
child: CircleAvatar(
radius: 64,
backgroundColor: Colors.pink,
),
)),
staggeredTiles: [
StaggeredTile.count(2, 2), // takes up 2 rows and 2 columns space
StaggeredTile.count(2, 1), // takes up 2 rows and 1 column
StaggeredTile.count(1, 2), // takes up 1 row and 2 column space
], // scatter them randomly
);
You can create class Person, and store profile name and image,
class Person {
String name;
String imageUrl;
}
and in your code can store all your persons in array
List<Person> persons = [Person(), Person(),....]
Wrap(
spacing: 30,
children: _children
);
List<Widget> _children {
List<Widget> _widgets = List<Widget>();
List<Persons> _randomList = persons.shuffle();
_randomList.forEach((person) {
_widgets.add(_buildProfile(person))
});
return _widgets;
}
I am displaying a list of data fetched from my sql database using DataCell, but I don't really like how it looks and want to switch it to display it using ListTile, this is the code that I am using to display it using DataCell:
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: [
DataColumn(
label: Text(''),
)
],
rows: _chatUsers
.map(
(user) => DataRow(cells: [
DataCell(
Text(user.firstNameUser),
// Add tap in the row and populate the
// textfields with the corresponding values to update
onTap: () {
// Set the Selected employee to Update
_selectedUser = user;
setState(() {
});
},
),
]),
)
.toList(),
),
),
);
You need to use the ListView widget for this.
There is a lot explained in that API reference section, I think you will be able to rework you app after reading.
So you will have a ListView with the childrenproperty set to smth like
_chatUsers
.map(
(user) =>
ListTile(
title: Text(user.firstNameUser),
// Add tap in the row and populate the
// textfields with the corresponding values to update
onTap: () {
// Set the Selected employee to Update
_selectedUser = user;
setState(() {
});
},
),
)
.toList()
I have a data table that scrolls horizontally and vertically due to the amount of data available. I want the top row which specifies the column names to always be visible when scrolling down vertically and the leftmost column to always be visible when scrolling horizontally.
#override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: Text(appTitle),
),
body: DataTableWidget(),
);
class DataTableWidgetState extends State<DataTableWidget> {
#override
Widget build(BuildContext context) {
final width = 100 * cityColumns.length;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
width: width * 1.4,
child: ListView(
children: <Widget>[
buildDataTable(),
],
),
),
);
}
Widget buildDataTable() => DataTable(
sortAscending: ascending,
sortColumnIndex: 0,
columns: cityColumns
.map(
(String column) => DataColumn(
label: Text(column),
onSort: (int columnIndex, bool ascending) => onSortColumn(
columnIndex: columnIndex, ascending: ascending),
),
)
.toList(),
rows: cities
.map((City city) => DataRow(
selected: selectedCities.contains(city),
cells: [
DataCell(Text('${city.name}')),
DataCell(Text('${city.nation}')),
DataCell(Text('${city.name2}')),
DataCell(Text('${city.nation2}')),
DataCell(Text('${city.name3}')),
DataCell(Text('${city.nation3}')),
DataCell(Text('${city.population}')),
DataCell(Text('${city.nation}')),
],
))
.toList(),
);
}
You can use the table_sticky_headers plugin to freeze table rows and columns. The row and column header can be populated using rowsTitleBuilder and columnsTitleBuilder.
StickyHeadersTable(
columnsLength: titleColumn.length,
rowsLength: titleRow.length,
columnsTitleBuilder: (i) => Text(titleColumn[i]), // column header
rowsTitleBuilder: (i) => Text(titleRow[i]), // row header
contentCellBuilder: (i, j) => Text(data[i][j]),
legendCell: Text('Sticky Legend'),
),