Dynamic Grids with GridView.builder in Flutter

Introduction to GridView.builder

In Flutter, a GridView is a scrollable 2D array of widgets, which is useful when you want to display content in a grid layout. If you want to build grids with dynamic or large numbers of items, the GridView.builder constructor is perfect for your needs. Unlike a standard GridView, which requires all the data to be passed upfront, GridView.builder allows you to create grids lazily. This means that it only builds the widgets that are currently visible on the screen, making it efficient for displaying large sets of data.

In this tutorial, you will learn how to work with GridView.builder to create dynamic grids.

Why Use GridView.builder?

  • Efficient: Only visible items are built, which improves performance, especially with large data sets.
  • Flexible: Can handle any kind of data, from static to dynamic content.
  • Customizable: You can control the number of columns, spacing, item aspect ratio, and much more.

How GridView.builder Works

The GridView.builder constructor requires two key parameters:

  1. itemCount: Specifies the total number of items to display in the grid.
  2. itemBuilder: A function that builds the grid items on demand. It is called only for the visible grid items.

Here's a basic syntax for GridView.builder:

GridView.builder(
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 2, // Number of columns
  ),
  itemCount: 10, // Total number of items
  itemBuilder: (context, index) {
    return Container(
      color: Colors.blue,
      child: Center(
        child: Text('Item $index'),
      ),
    );
  },
)

Key Parameters of GridView.builder

  1. gridDelegate:

    • This is responsible for defining the grid’s layout.
    • Common delegates are:
      • SliverGridDelegateWithFixedCrossAxisCount: Specifies a fixed number of columns.
      • SliverGridDelegateWithMaxCrossAxisExtent: Specifies the maximum width for each grid item.

    Example:

    SliverGridDelegateWithFixedCrossAxisCount(
      crossAxisCount: 2, // Number of columns
      crossAxisSpacing: 10, // Horizontal spacing between items
      mainAxisSpacing: 10, // Vertical spacing between items
    )
    
  2. itemCount:
    1. The total number of items to be displayed in the grid.
    2. This value should match the length of the list or data set you are displaying.
  3. itemBuilder:
    1. A function that returns the widget for each grid item.
    2. It takes two arguments: context (the build context) and index (the index of the current item).

Example 1: Basic GridView.builder

Here’s how to create a simple grid with GridView.builder:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('GridView.builder Example'),
        ),
        body: GridView.builder(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2,
            crossAxisSpacing: 10,
            mainAxisSpacing: 10,
          ),
          itemCount: 20,
          itemBuilder: (context, index) {
            return Container(
              color: Colors.blueAccent,
              child: Center(
                child: Text(
                  'Item $index',
                  style: TextStyle(color: Colors.white),
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}

Explanation:

  • SliverGridDelegateWithFixedCrossAxisCount: This sets up a grid with 2 columns, and there is 10-pixel spacing between rows and columns.
  • itemCount: We have 20 items in the grid.
  • itemBuilder: The grid items are displayed using a simple Container widget with a text label.

Example 2: Dynamic GridView.builder with List Data

In real-world apps, you often fetch dynamic data from a server or a local database. Let’s use a list of images to dynamically populate a grid.

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Dynamic GridView.builder Example'),
        ),
        body: DynamicGrid(),
      ),
    );
  }
}

class DynamicGrid extends StatelessWidget {
  final List<String> imageUrls = [
    'https://via.placeholder.com/150',
    'https://via.placeholder.com/150',
    'https://via.placeholder.com/150',
    'https://via.placeholder.com/150',
    // Add more URLs here
  ];

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 3, // 3 columns
        crossAxisSpacing: 10,
        mainAxisSpacing: 10,
      ),
      itemCount: imageUrls.length,
      itemBuilder: (context, index) {
        return Image.network(imageUrls[index]);
      },
    );
  }
}

Explanation:

  • We create a list of image URLs called imageUrls and use it to build our dynamic grid.
  • The GridView.builder uses the imageUrls list to display each image in the grid.
  • Each item in the grid is an Image.network, which loads an image from the internet.

Customizing the GridView

You can customize the appearance and behavior of your grid in various ways. Some options include:

1. Adjusting the Number of Columns

You can change the number of columns based on the screen size using MediaQuery.

int crossAxisCount = MediaQuery.of(context).size.width > 600 ? 4 : 2;

2. Using SliverGridDelegateWithMaxCrossAxisExtent

This delegate allows you to specify the maximum width of each grid item instead of the number of columns. This is useful if you want items to adjust dynamically based on available screen space.

GridView.builder(
  gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
    maxCrossAxisExtent: 200, // Maximum width of each item
    crossAxisSpacing: 10,
    mainAxisSpacing: 10,
  ),
  itemCount: 10,
  itemBuilder: (context, index) {
    return Container(
      color: Colors.green,
      child: Center(child: Text('Item $index')),
    );
  },
)

3. Adding Scroll Direction

By default, GridView scrolls vertically. However, you can change the scroll direction to horizontal.

GridView.builder(
  scrollDirection: Axis.horizontal, // Horizontal scrolling
  gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
    crossAxisCount: 1, // Only 1 item per row
  ),
  itemCount: 10,
  itemBuilder: (context, index) {
    return Container(
      color: Colors.red,
      child: Center(child: Text('Item $index')),
    );
  },
)

Conclusion

The GridView.builder is a powerful widget for creating dynamic, scrollable grids in Flutter. It’s highly efficient, flexible, and easy to customize, making it ideal for displaying large or dynamic sets of data. In this tutorial, you've learned how to set up a basic grid, work with dynamic data, and apply customizations like adjustable column numbers and horizontal scrolling.