Flutter Grid View from 2D array

Grid View is really helpful when you have 2D array of items to display on screen and you would like to keep the number of cross axis items consistent (Number of items across the screen)

Consider you are having a tile based game where you are trying to build the map or when you have lots of items to display in e-commerce website during which procedural generation of these items is preferred.

Create a list which holds the items you are trying to display.

List<List<String>> gridState = [  [‘’, ‘T’, ‘’, ‘’, ‘’, ‘’, ‘’, ‘P2’],
[‘’, ‘’, ‘’, ‘T’, ‘’, ‘’, ‘’, ‘’],
[‘B’, ‘T’, ‘’, ‘’, ‘’, ‘B’, ‘’, ‘’],
[‘’, ‘’, ‘’, ‘B’, ‘’, ‘’, ‘’, ‘T’],
[‘’, ‘’, ‘T’, ‘’, ‘’, ‘T’, ‘’, ‘’],
[‘’, ‘’, ‘’, ‘’, ‘’, ‘’, ‘’, ‘B’],
[‘’, ‘’, ‘’, ‘’, ‘T’, ‘’, ‘’, ‘’],
[‘P1’, ‘’, ‘’, ‘’, ‘’, ‘’, ‘T’, ‘’],
];

This 2D array represents the items to be displayed on the screen. Each character corresponds to different types of tiles. For example, T => Tree, B=>Bush, P1=> Player 1, P2 => Player 2.

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Game World'),
),
body: _buildGameBody(),
);
}

We are starting with familiar build function and _buildGameBody() is where we will transform the data into separate widget on Screen.

Widget _buildGameBody() {
int gridStateLength = gridState.length;
return Column(
children: <Widget>[
AspectRatio(
aspectRatio: 1.0,
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.black, width: 2.0)
),
child: GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: gridStateLength,
),
itemBuilder: _buildGridItems,
itemCount: gridStateLength * gridStateLength,
),
),
),
]);
}

Aspect Ratio

This widget is useful when you want your layout to be in certain ratio. I have specified the aspectRatio as 1 and so it will make the grid with equal width and height. This also help in making the layout dynamic by not specifying any height value to the widget. If the aspectRatio is 1 it will calculate the available width and apply the same to height.

GridView.builder

gridDelegate - controls the layout of the children within the GridView.

SliverGridDelegateWithFixedCrossAxisCount helps you when you require grid with fixed number of rows or fixed number of columns. You can specify the number of items you require and it will build the layout of the grid based on this count. I have specified this as gridStateLength which has the length of gridState variable. itemCount property for this example will the square of gridStateLength because we have a matrix of Y x Y.

Widget _buildGridItems(BuildContext context, int index) {
int gridStateLength = gridState.length;
int x, y = 0;
x = (index / gridStateLength).floor();
y = (index % gridStateLength);
return GestureDetector(
onTap: () => _gridItemTapped(x, y),
child: GridTile(
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.black, width: 0.5)
),
child: Center(
child: _buildGridItem(x, y),
),
),
),
);
}

This method is responsible for converting the index of the grid items in the gridState variable into x (row) , y (column) which would be easy for accessing the array. It also handles the GestureDetector which helps in finding the user interaction with a particular grid item. Here, I am calling another method _buildGridItem with x and y values which will be responsible for creating the specific widget for different types of characters in 2D array.

Widget _buildGridItem(int x, int y) {
switch (gridState[x][y]) {
case '':
return Text('');
break;
case 'P1':
return Container(
color: Colors.blue,
);
break;
case 'P2':
return Container(
color: Colors.yellow,
);
break;
case 'T':
return Icon(
Icons.terrain,
size: 40.0,
color: Colors.red,
);
break;
case 'B':
return Icon(Icons.remove_red_eye, size: 40.0);
break;
default:
return Text(gridState[x][y].toString());
}
}

Finally, we have the function which build widget based on the type of character in the array. We have a switch control statement followed by the list of different types of string character and we are building separate widget for each of them. At the end, there is a default case is a safety net which get executed if the character does not match any of the mentioned case.

Final Result !!

Wrapping Up

Hope you enjoyed this short example of creating a grid view in flutter. Feel free to share your comments. If anyone is interested in seeing more on this turn-based game let me know and I will try to continue this series.

Happy Fluttering!!

The Flutter Pub is a medium publication to bring you the latest and amazing resources such as articles, videos, codes, podcasts etc. about this great technology to teach you how to build beautiful apps with it. You can find us on Facebook, Twitter, and Medium or learn more about us here. We’d love to connect! And if you are a writer interested in writing for us, then you can do so through these guidelines.

Programmer, Mobile Technology Enthusiast who is passionate about providing the best User Experience | #Flutter #Xamarin #Ionic| Writer at FlutterPub