A grid is an arrangement of elements in rows and columns.
So far, our Apps have been very vertical. Everything flowed from top to bottom in an endless list. But what if we want to make a photo gallery like Instagram? Or a dashboard with large buttons?
For that, we need to organize content in two dimensions. We need a Grid.
In Flutter, the widget responsible for this is the GridView. It works very similarly to ListView, but adds a layer of complexity: we have to decide how many columns we want and what shape the cells will have.
GridView.count: a fixed number of columns
If you know exactly how many columns you want (e.g., “I want 2 fixed columns”), the simplest constructor is GridView.count.
It’s perfect for static menus or simple galleries.
GridView.count(
crossAxisCount: 2, // Number of columns (cross axis)
mainAxisSpacing: 10, // Vertical space between rows
crossAxisSpacing: 10, // Horizontal space between columns
padding: EdgeInsets.all(20), // External margin of the grid
children: [
Container(color: Colors.red, child: Center(child: Text("1"))),
Container(color: Colors.blue, child: Center(child: Text("2"))),
Container(color: Colors.green, child: Center(child: Text("3"))),
Container(color: Colors.orange, child: Center(child: Text("4"))),
],
)
Aspect Ratio
By default, GridView tries to make cells square (1:1 aspect ratio). But sometimes we want rectangular cards (wider than they are tall, or vice versa).
To control this we use the childAspectRatio property.
- 1.0: Perfect square.
- < 1.0: Taller than wide (Portrait, e.g., 0.7 for movie posters).
- > 1.0: Wider than tall (Landscape, e.g., 1.5 for news cards).
GridView.count(
crossAxisCount: 2,
childAspectRatio: 1.5, // Rectangular landscape cells
children: [...],
)
GridView.extent: adaptive grids
The problem with GridView.count is that it’s rigid. If you set crossAxisCount: 2, you’ll see 2 columns on a small phone (looking fine) and 2 columns on a 12-inch tablet (resulting in gigantic, ugly cells).
To solve this, we use GridView.extent.
Instead of telling it “how many columns”, we tell it: “What is the MAXIMUM width each cell can have?”. Flutter will automatically calculate how many fit.
GridView.extent(
maxCrossAxisExtent: 150, // Each cell will measure AT MOST 150px in width
children: [...],
)
- On a 300px wide phone -> 2 cells fit.
- On a 900px wide tablet -> 6 cells fit.
This is the easiest way to make your design Responsive without complicating things with manual screen calculations.
GridView.builder: dynamic data
As with lists, if we are going to display 1,000 photos downloaded from the internet, we cannot use the normal constructors. We need lazy rendering.
We will use GridView.builder. But here the syntax gets a bit more complex because we need a “delegate” (gridDelegate) to control the geometry.
The gridDelegate is the object that contains the mathematical logic on how to distribute the tiles.
GridView.builder(
itemCount: 100, // We have 100 items
// Define the grid structure here
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, // 3 Fixed columns
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
// Build the item on demand (same as ListView)
itemBuilder: (context, index) {
return Container(
color: Colors.teal[100 * (index % 9)],
child: Center(child: Text('Item $index')),
);
},
)
The two main delegates
The class name is long (SliverGridDelegateWith...), but there are two delegates we will use regularly:
SliverGridDelegateWithFixedCrossAxisCount: Equivalent to.count. You set the number of columns.SliverGridDelegateWithMaxCrossAxisExtent: Equivalent to.extent. You set the maximum width of the item to make it responsive.
A Design Tip: SliverGrid
Although GridView is powerful, sometimes you’ll want to mix a normal list with a grid on the same screen (for example, a header, then a grid of photos, and then a footer).
Nesting a scrollable GridView inside a ListView often causes constraint and scrolling conflicts. It can be solved in small cases with shrinkWrap and proper physics, but for large compositions it’s better to share a single scroll system.
For these advanced cases, CustomScrollView and slivers are used. It’s an advanced topic, but it’s worth remembering the name: if you need to combine a header, a list, and a grid under the same scroll, look up SliverList and SliverGrid.