Table in Flutter: Beyond The Basics
A Table
is a multi-child layout widget which is used to represent data in an organized row-column layout.
Today we will take a look at various properties that are not regularly used while implementing Table
widget but can be very useful to render data on screen and how we can make use of them to customize its layout with examples, so let’s get started.
A basic representation of a 2 x 2 Table
is as below:
Code representation for above layout using Table
widget will be:
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.all(10),
child: Table(
border: TableBorder.all(),
children: [
TableRow(children: [
Text('Sport', textAlign: TextAlign.center, style: TextStyle(fontWeight: FontWeight.bold)),
Text('Total Players', textAlign: TextAlign.center, style: TextStyle(fontWeight: FontWeight.bold)),
]),
TableRow(children: [
Text('Soccer', textAlign: TextAlign.center),
Text('11', textAlign: TextAlign.center),
]),
],
),
),
]))
Above we see various keywords such as border
, children
, TableRow
that helps to form the Table
layout.
TableRow
represents each row (horizontal layout) in the Table
and takes List of children
that forms cells
in each row.
Let’s take a look now at various properties at Table
and TableRow
level that we can use and how they help to enhance and customize the entire Table
layout.
- border
This property belongs to TableBorder
class and offers the way borders will be displayed in and around a Table.
In above code snippet, we used border: TableBorder.all()
, a most common and simple usage of border
property, which specifies borders inside and around the entire table.
Using this property, we can specify various border layouts. Let’s see them one by one.
If we want to specify horizontal borders only inside the table, we can use horizontalInside
parameter and specify border side values and styles, as below:
child: Table(
border: TableBorder(horizontalInside: BorderSide(width: 1, color: Colors.blue, style: BorderStyle.solid)),
Similarly, if we want vertical borders only inside the table, we can use verticalInside
parameter and specify border side values and styles, as below:
child: Table(
border: TableBorder(verticalInside: BorderSide(width: 1, color: Colors.blue, style: BorderStyle.solid)),
We can also specify individual borders, such as top
, bottom
, left
or right
using same values and styles, as below:
child: Table(
border: TableBorder(top: BorderSide(color: Colors.blue, width: 1), bottom: BorderSide(color: Colors.blue, width: 1))
Similarly, we can have borders only at left
and right
, as below:
child: Table(
border: TableBorder(left: BorderSide(color: Colors.blue, width: 1 ), right: BorderSide(color: Colors.blue, width: 1))
If we want a particular border style around the table and different border style inside it, we can use symmetric
property that has inside
and outside
parameters to achieve the desired result, as below:
child: Table(
border: TableBorder.symmetric(inside: BorderSide(width: 2, color: Colors.blue), outside: BorderSide(width: 3, color: Colors.blue)),
We can also use only inside
or outside
parameters of symmetric
that uniformly shows the border, as below:
child: Table(
border: TableBorder.symmetric(inside: BorderSide(width: 2, color: Colors.blue)),
child: Table(
border: TableBorder.symmetric(outside: BorderSide(width: 2, color: Colors.blue)),
TableBorder.lerp method linearly interpolates (ie, generates a new value based on existing set of values) and applies to the specified border sides:
child: Table(
border: TableBorder.lerp(TableBorder(top: BorderSide(width: 2, color: Colors.red)), TableBorder(bottom: BorderSide(width: 4, color: Colors.green)), 0.5),
- columnWidths:
When we implement Table
widget, it renders the layout with default column widths. There could be requirement when we want column width to be flexible or layout to use minimum available width per the data content in the cells. At this point, we can make use of columnWidths
property.
Using columnWidths
property, we can specify custom width to each column. This property uses Map
data type to identify and match each column
and then takes following mechanisms to size each of them:
- FixedColumnWidth : Sizes the column per specified width.
child: Table(
border: TableBorder.symmetric(inside: BorderSide(width: 1, color: Colors.blue), outside: BorderSide(width: 1)),
columnWidths: {
0: FixedColumnWidth(80),
1: FixedColumnWidth(80)
},
Another implementation of columnWidths
is by explicitly specifying the Map
data type, as:
columnWidths: Map.from({
0: FixedColumnWidth(50),
1: FixedColumnWidth(50)
}),
- FractionColumnWidth : Sizes the column to a fraction of entire table’s maximum width. The value to be passed as a fraction should not be > 1 for each column and total fraction width of all columns should not exceed 1.
child: Table(
border: TableBorder.symmetric(inside: BorderSide(width: 1, color: Colors.blue), outside: BorderSide(width: 1)),
columnWidths: {
0: FractionColumnWidth(0.7),
1: FractionColumnWidth(0.3)
},
- FlexColumnWidth: Sizes the column based on any remaining space after table is rendered. ie, the remaining space is distributed according to the ratio of the column’s flex factor to the total flex factor.
child: Table(
border: TableBorder.symmetric(inside: BorderSide(width: 1, color: Colors.blue), outside: BorderSide(width: 1)),
columnWidths: {
0: FlexColumnWidth(15),
1: FlexColumnWidth(5)
},
- IntrinsicColumnWidth: Sizes the column based on the width of the content in each cell, ie, the column width increases or shrinks depending upon the length of the content in the cell.
child: Table(
border: TableBorder.symmetric(inside: BorderSide(width: 1, color: Colors.blue), outside: BorderSide(width: 1)),
columnWidths: {
0: IntrinsicColumnWidth(),
1: IntrinsicColumnWidth()
},
If content in a cell is bigger in width, the column width auto-sizes.
- defaultColumnWidth: If we want to set a specific width to all columns at once before table is rendered, then we can use this property and pass any one mechanism as mentioned above.
child: Table(
border: TableBorder.symmetric(inside: BorderSide(width: 1, color: Colors.blue), outside: BorderSide(width: 1)),
defaultColumnWidth: FixedColumnWidth(150),
- defaultVerticalAlignment: This property helps to align the contents in all rows at the
Table
level, ie, if we want to align contents at thetop
of the row, or at thebottom
or in themiddle
, then we can use this property.
child: Table(
border: TableBorder.symmetric(
inside: BorderSide(width: 1, color: Colors.blue),
outside: BorderSide(width: 1)),
defaultColumnWidth: FixedColumnWidth(150),
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
Above we saw various properties at Table
level. Now we’ll take a look at some of the properties that are applicable for each row.
- decoration: This property allows to decorate a given row with color. Let’s say if we want to color heading of a table or color every alternate row in a table, then we can make use of this property.
child: Table(
border: TableBorder.symmetric(
inside: BorderSide(width: 1, color: Colors.blue),
outside: BorderSide(width: 1)),
defaultColumnWidth: FixedColumnWidth(150),
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [
TableRow(
decoration: BoxDecoration(color: Colors.grey[200]),
TableCell: This class is used as one of the children inside TableRow
widget, that helps to control how the data in the cell is to be aligned. It has verticalAlignment
property that aligns the data in a particular cell vertically such as top
, bottom
or in the middle
.
Specifying verticalAlignment
for each TableCell
will align the data for that cell accordingly.
TableRow(children: [
TableCell(
verticalAlignment: TableCellVerticalAlignment.middle,
child: Text('Soccer',
style: TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.center)),Column(children: <Widget>[Text('Ronaldo'), Text('Messi')])
Note that, with TableCell's
verticalAlignment
property, the alignment is implemented on particular cell, whereas, the defaultVerticalAlignment
property aligns its data to the entire table.
In this article, we saw how we can make use of various properties at Table
, TableRow
and TableCell
level that helps to render table per our needs along with customizing the layout. Using these properties, we can render simple as well as complex table designs in UI.
That’s all I have for today. Thanks for reading and feel free to comment below your thoughts / suggestion / feedback on this topic.
I can be reached via Twitter and LinkedIn.
You may check out my profile below for other articles I wrote on Flutter.