Reputation: 1500
I have a 2 column flutter DataTable and the lines don't span the screen width leaving lots of white space. I found this issue
https://github.com/flutter/flutter/issues/12775
That recommended wrapping the DataTable in a SizedBox.expand widget but that does not work produces RenderBox was not laid out:
SizedBox.expand(
child: DataTable(columns:_columns, rows:_rows),
),
Full widget
@override
Widget build(BuildContext context) {
return new Scaffold(
body:
SingleChildScrollView(
child: Column(
children: [Container(Text('My Text')),
Container(
alignment: Alignment.topLeft,
child: SingleChildScrollView(scrollDirection: Axis.horizontal,
child: SizedBox.expand(
child: DataTable(columns:_columns, rows:_rows),
),
),
),
]))
);
}
Upvotes: 32
Views: 38679
Reputation: 1
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columnSpacing: MediaQuery.of(context).size.width * 0.2,
columns: const [
DataColumn(label: Text('Product Name')),
DataColumn(label: Text('Product Price')),
DataColumn(label: Text('Product Type')),
DataColumn(label: Text('Product Category')),
DataColumn(label: Text('Product Description')),
],
rows: productsList.map((product) {
return DataRow(cells: [
DataCell(Text(product.productName)),
DataCell(Text(product.price)),
DataCell(Text(product.typeOfProduct)),
DataCell(Text(product.categoryOfProduct)),
DataCell(Text(product.description)),
]);
}).toList(),
),
),
simple solution is to use columnSpacing and use this formula (width of screen / number of columns === width of the screen * (1/number of columns)) that is columnSpacing: MediaQuery.of(context).size.width * 0.2
because in my case column count is 5 so (screen width * (1/5 which is 0.2)).
hope this help Don't forget to wrap the DataTable with SingleChildScrollView
Upvotes: 0
Reputation: 684
SingleChildScrollView(
child: Card(
child: SizedBox(
width: double.infinity,
child: DataTable(columns:_columns, rows:_rows),
),
),
),
Upvotes: 0
Reputation: 3354
Simple Answer:
Wrap your datatable with a Container()
with width: double.infinity()
.
Container(
width: double.infinity,
child: DataTable(
..
.
My Prefered Way
You can use DataTable 2 Package at pub.dev
https://pub.dev/packages/data_table_2
This package will give you the DataTable2()
widget which will expand to the available space by default. Also you get more options like ColumnSize
etc.
Upvotes: 4
Reputation: 489
just wrap your DataTable with Sizedbox and give width to double.infinity.
SizedBox(
width: double.infinity,
child: DataTable()
)
Upvotes: 6
Reputation: 2132
Just wrap the data table with a container having fixed width defined and everything should work.
Even when you need multiple tables in one screen this worked well for me as of flutter 2.2.3.
final screenWidth = MediaQuery.of(context).size.width;
Scaffold(
body: SingleChildScrollView(child:Container(
child: Column(
children: [
Container(
width: screenWidth, // <- important for full screen width
padding: EdgeInsets.fromLTRB(0, 2, 0, 2),
child: buildFirstTable() // returns a datatable
),
Container(
width: screenWidth, // <- this is important
padding: EdgeInsets.fromLTRB(0, 2, 0, 2),
child: buildSecondTable() // returns a datatable
)
])
))
)
This also works for single table just wrap with container with desired width.
Upvotes: 1
Reputation: 151
Set your datatable in Container and make container's width as double.infinity
Container(
width: double.infinity,
child: DataTable(
columns: _columns,
rows: _rows,
));
Upvotes: 14
Reputation: 1605
This is an issue, incompleteness, in an otherwise beautiful Widget which is the DataTable, I faced this issue in a production code, this solution worked on more than half of the lab devices:
ConstrainedBox(
constraints: BoxConstraints.expand(
width: MediaQuery.of(context).size.width
),
child: DataTable( // columns and rows.),)
But you know what suprisingly worked on %100 of the devices ? this:
Row( // a dirty trick to make the DataTable fit width
children: <Widget>[
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: DataTable(...) ...]//row children
Note: The Row has only one child Expanded which in turn enclose a SingleChildScrollView which in turn enclose the DataTable.
Note that this way you cant use SingleChileScrollView with scrollDirection: Axis.horizontal, in case you need it, but you don
t otherwise this question would be irrelevant to your use case.
In case someone of the Flutter team reads this, please enrich the DataTable Widget, it will make flutter competitive and powerful, flutter may eclipse androids own native API if done right.
Upvotes: 19
Reputation: 975
For DataTable widget this code has worked for me regarding dataTable width as match parent to device-width,
Code snippet:
ConstrainedBox(
constraints:
BoxConstraints.expand(
width: MediaQuery.of(context).size.width
),
child:
DataTable(
// inside dataTable widget you must have columns and rows.),)
and you can remove space between columns by using attribute like
columnSpacing: 0,
Note:
using ConstrainedBox widget solves your issue,
constraints: BoxConstraints.expand(width: MediaQuery.of(context).size.width),
Complete Code :
Note: In this sample code, I covered sorting and editing DataTable widget concepts.
In Lib Folder you must have this class
main.dart class code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'DataTableDemo.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: DataTableDemo(),
);
}
}
DataTableDemo.dart class code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'customer.dart';
class DataTableDemo extends StatefulWidget {
DataTableDemo() : super();
final String title = "Data Table";
@override
DataTableDemoState createState() => DataTableDemoState();
}
class DataTableDemoState extends State<DataTableDemo> {
List<customer> users;
List<customer> selectedUsers;
bool sort;
TextEditingController _controller;
int iSortColumnIndex = 0;
int iContact;
@override
void initState() {
sort = false;
selectedUsers = [];
users = customer.getUsers();
_controller = new TextEditingController();
super.initState();
}
onSortColum(int columnIndex, bool ascending) {
if (columnIndex == 0) {
if (ascending) {
users.sort((a, b) => a.firstName.compareTo(b.firstName));
} else {
users.sort((a, b) => b.firstName.compareTo(a.firstName));
}
}
}
onSelectedRow(bool selected, customer user) async {
setState(() {
if (selected) {
selectedUsers.add(user);
} else {
selectedUsers.remove(user);
}
});
}
deleteSelected() async {
setState(() {
if (selectedUsers.isNotEmpty) {
List<customer> temp = [];
temp.addAll(selectedUsers);
for (customer user in temp) {
users.remove(user);
selectedUsers.remove(user);
}
}
});
}
SingleChildScrollView dataBody() {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints.expand(width: MediaQuery.of(context).size.width),
child: DataTable(
sortAscending: sort,
sortColumnIndex: iSortColumnIndex,
columns: [
DataColumn(
label: Text("FIRST NAME"),
numeric: false,
tooltip: "This is First Name",
onSort: (columnIndex, ascending) {
setState(() {
sort = !sort;
});
onSortColum(columnIndex, ascending);
}),
DataColumn(
label: Text("LAST NAME"),
numeric: false,
tooltip: "This is Last Name",
),
DataColumn(label: Text("CONTACT NO"), numeric: false, tooltip: "This is Contact No")
],
columnSpacing: 2,
rows: users
.map(
(user) => DataRow(
selected: selectedUsers.contains(user),
onSelectChanged: (b) {
print("Onselect");
onSelectedRow(b, user);
},
cells: [
DataCell(
Text(user.firstName),
onTap: () {
print('Selected ${user.firstName}');
},
),
DataCell(
Text(user.lastName),
),
DataCell(Text("${user.iContactNo}"),
showEditIcon: true, onTap: () => showEditDialog(user))
]),
)
.toList(),
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SafeArea(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
// verticalDirection: VerticalDirection.down,
children: <Widget>[
Expanded(
child: Container(
child: dataBody(),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Padding(
padding: EdgeInsets.all(20.0),
child: OutlineButton(
child: Text('SELECTED ${selectedUsers.length}'),
onPressed: () {},
),
),
Padding(
padding: EdgeInsets.all(20.0),
child: OutlineButton(
child: Text('DELETE SELECTED'),
onPressed: selectedUsers.isEmpty ? null : () => deleteSelected(),
),
),
],
),
],
),
),
);
}
void showEditDialog(customer user) {
String sPreviousText = user.iContactNo.toString();
String sCurrentText;
_controller.text = sPreviousText;
showDialog(
barrierDismissible: false,
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Edit Contact No"),
content: new TextFormField(
controller: _controller,
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: 'Enter an Contact No'),
onChanged: (input) {
if (input.length > 0) {
sCurrentText = input;
iContact = int.parse(input);
}
},
),
actions: <Widget>[
new FlatButton(
child: new Text("Save"),
onPressed: () {
setState(() {
if (sCurrentText != null && sCurrentText.length > 0) user.iContactNo = iContact;
});
Navigator.of(context).pop();
},
),
new FlatButton(
child: new Text("Cancel"),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
customer.dart class code
class customer {
String firstName;
String lastName;
int iContactNo;
customer({this.firstName, this.lastName,this.iContactNo});
static List<customer> getUsers() {
return <customer>[
customer(firstName: "Aaryan", lastName: "Shah",iContactNo: 123456897),
customer(firstName: "Ben", lastName: "John",iContactNo: 78879546),
customer(firstName: "Carrie", lastName: "Brown",iContactNo: 7895687),
customer(firstName: "Deep", lastName: "Sen",iContactNo: 123564),
customer(firstName: "Emily", lastName: "Jane", iContactNo: 5454698756),
];
}
}
Upvotes: 8
Reputation: 3219
SizedBox.expand
results in the DataTable
taking an infinite height which the SingleChildScrollView
won't like. Since you only want to span the width of the parent, you can use a LayoutBuilder
to get the size of the parent you care about and then wrap the DataTable
in a ConstrainedBox
.
Widget build(BuildContext context) {
return Scaffold(
body: LayoutBuilder(
builder: (context, constraints) => SingleChildScrollView(
child: Column(
children: [
const Text('My Text'),
Container(
alignment: Alignment.topLeft,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(minWidth: constraints.minWidth),
child: DataTable(columns: [], rows: []),
),
),
),
],
),
),
),
);
}
Upvotes: 22
Reputation: 103421
You can add the crossAxisAlignment
for your Column
to strech
crossAxisAlignment: CrossAxisAlignment.stretch
Upvotes: 35