Table in Flutter: Beyond The Basics

Darshan Kawar
Flutter Community
Published in
7 min readMay 22, 2020

--

Photo by GEORGE DESIPRIS on Unsplash

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)),
TableBorder : horizontalInside

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)),
TableBorder: verticalInside

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))
TableBorder: top, bottom

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))
TableBorder: left, right

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)),
TableBorder.symmetric

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)),
TableBorder.symmetric: inside
child: Table(
border: TableBorder.symmetric(outside: BorderSide(width: 2, color: Colors.blue)),
TableBorder.symmetric: outside

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),
TableBorder.lerp: top, bottom
  • 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)
},
columnWidth: FixedColumnWidth

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)
},
columnWidth: FractionColumnWidth
  • 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)
},
columnWidth: FlexColumnWidth
  • 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()
},
columnWidth: 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),
defaultColumnWidth
  • defaultVerticalAlignment: This property helps to align the contents in all rows at the Table level, ie, if we want to align contents at the top of the row, or at the bottom or in the middle, 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,
defaultVerticalAlignment: middle
defaultVerticalAlignment: top
defaultVerticalAlignment: bottom

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]),
TableRow decoration

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')])
TableCell : verticalAlignment: middle, top, bottom

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.

--

--

Darshan Kawar
Flutter Community

Open Source Support Engineer For Flutter @nevercodeHQ. Android Nanodegree Certified. Previously, Android Automation Test Engineer.