Building a Infinite Color Grid App in Flutter with Dart
Tags: flutter, dart, beginners, tutorial
Published: 2023-07-17 13:43:55

## Building a Infinite Color Grid App in Flutter with Dart

In this tutorial, we'll create a Flutter app that displays a grid of random colors. The app will generate new colors every second and display them in a grid layout. We'll use the Dart programming language along with the Flutter framework to implement this color grid application.

### Prerequisites

Before you proceed, make sure you have the following installed:

1. Flutter SDK: Install Flutter from the official website [https://flutter.dev/docs/get-started/install](https://flutter.dev/docs/get-started/install).

2. Flutter-compatible code editor: Choose your preferred code editor; Visual Studio Code with the Flutter extension is recommended.

### Creating the Flutter Project

1. Open your terminal or command prompt and run the following command to create a new Flutter project:

```bash
flutter create color_grid_app
```

2. Change into the project directory:

```bash
cd color_grid_app
```

3. Replace the content of the `lib/main.dart` file with the following code:

```dart
// main.dart
import 'package:flutter/material.dart';

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

class ColorGridApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Home(),
    );
  }
}
```

### Implementing the Color Grid

## Step - 1

### Adding Random Color Generation

To generate random colors for the grid, we'll create an extension on a `String` , which will generate a random hex color.

This extension `RandomColorExtension` on the `String` class contains two static methods: `_randomString()` and `randomColorHex()`. These methods are used to generate random hexadecimal color codes.

1. `_randomString()`: This private static method generates a random string of length 6 containing characters from the constant `letters`. It uses the `Random` class to select random characters from the `letters` string and concatenates them to build a 6-character string. The `letters` string includes digits (0-9) and lowercase letters (a-z), providing a pool of characters for the random string generation.

2. `randomColorHex()`: This static method uses the previously defined `_randomString()` to generate a random hexadecimal color code. It does this by calling `_randomString()` and storing the result in the variable `hexColor`. Then, it uses a `do-while` loop to keep generating a new `hexColor` until it matches the pattern defined by the regular expression `r'^[0-9a-fA-F]{6}$'`. The regular expression `^[0-9a-fA-F]{6}$` ensures that the `hexColor` is a valid hexadecimal color code with exactly 6 characters and includes only digits (0-9) and letters (a-f, A-F). Once a valid `hexColor` is generated, the method returns it.

```dart

extension RandomColorExtension on String {
  static const letters = "0123456789abcdefghijklmnopqrstuvwxyz";

  static String _randomString() {
    final Random random = Random();
    String result = '';

    for (int i = 0; i < 6; i++) {
      int randomIndex = random.nextInt(letters.length);
      result += letters[randomIndex];
    }
    return result;
  }

  static String randomColorHex() {
    String hexColor;
    do {
      hexColor = _randomString();
    } while (!RegExp(r'^[0-9a-fA-F]{6}$').hasMatch(hexColor));

    return "0xFF$hexColor";
  }
}
```

## Step - 2

Now, let's implement the `FutureColor` Function, which will display the color grid inside a Widget.

The function `futureColor()` is an asynchronous function in Flutter, which means it can perform operations asynchronously and return a `Future` that will eventually hold the result. Let's break down the function step by step:

1. `final List<String> colorList = <String>[];`: This creates an empty list of strings named `colorList`. This list will be used to store the generated random color values.

2. `String randomColorName = "";`: This initializes an empty string named `randomColorName`. It will be used to hold the randomly generated hexadecimal color string.

3. `Future<List<String>> futureColor() async {`: This defines the function `futureColor()`, which returns a `Future` containing a list of strings (`List<String>`). The `async` keyword indicates that this function can perform asynchronous operations using `await`.

4. `await Future.delayed(const Duration(seconds: 1), () { ... });`: This line uses `await` to pause the execution of the function for one second (`Duration(seconds: 1)`) before continuing. Inside the `() { ... }` block, we generate a random hexadecimal color string using `RandomColorExtension.randomColorHex()` and store it in `randomColorName`.

5. `randomColorName = "0xFF${RandomColorExtension.randomColorHex()}";`: Here, we concatenate the prefix `"0xFF"` to the random color string. In Flutter, color values are represented in 32-bit integers, where the first 8 bits (the prefix "0xFF") represent the alpha channel, and the remaining 24 bits represent the RGB color. The alpha channel determines the opacity of the color, and "0xFF" means the color is fully opaque.

6. `colorList.add(randomColorName);`: The generated color string is added to the `colorList` list.

7. `debugPrint("HexColor: $randomColorName");`: This line prints the hexadecimal color string to the debug console. It's helpful for debugging purposes.

8. `setState(() {});`: This `setState` function call tells Flutter that the internal state of the widget has changed, and it needs to be rebuilt. Since we added a new color to the `colorList`, this will trigger a rebuild of the widget, and the new color will be displayed in the grid.

9. `return colorList;`: Finally, the function returns the `colorList`, which will be wrapped in a `Future`. When the `await Future.delayed` completes its one-second delay, the future will complete with the updated `colorList`.

In summary, the `futureColor()` function generates a random hexadecimal color string, adds it to a list of colors, and then returns that list as a `Future`. The `Future` allows other parts of the code to wait for the function to complete and get access to the updated list of colors. The app uses this function to generate and display new random colors every second in the color grid.

```dart
  final List<String> colorList = <String>[];
  String randomColorName = "";
  Future<List<String>> futureColor() async {
    await Future.delayed(
      const Duration(seconds: 1),
      () {
        randomColorName = RandomColorExtension.randomColorHex();
        colorList.add(randomColorName);
        debugPrint("HexColor: $randomColorName");
        setState(() {});
      },
    );
    return colorList;
  }
```

## Step - 3

 Now Lets Create a Custom Grid Widget

```dart
import 'package:flutter/material.dart';

class BoxGridView extends StatelessWidget {
  final List<String> cardColors;
  const BoxGridView({super.key, required this.cardColors});

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        crossAxisSpacing: 10.0,
        mainAxisSpacing: 10.0,
      ),
      itemCount: cardColors.length,
      itemBuilder: (context, index) {
        return Card(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(15.0),
          ),
          elevation: 8,
          color: Color(int.parse(cardColors[index])),
          child: Center(
            child: SelectableText(
              cardColors[index],
              cursorColor: Colors.blue,
              contextMenuBuilder: (context, editableTextState) {
                return AdaptiveTextSelectionToolbar.buttonItems(
                  anchors: editableTextState.contextMenuAnchors,
                  buttonItems: <ContextMenuButtonItem>[
                    ContextMenuButtonItem(
                      onPressed: () {
                        editableTextState
                            .copySelection(SelectionChangedCause.toolbar);
                      },
                      type: ContextMenuButtonType.copy,
                    ),
                  ],
                );
              },
              showCursor: true,
              style: const TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
                color: Colors.white,
              ),
            ),
          ),
        );
      },
    );
  }
}
```

## Full Code

```dart
void main() {
  runApp(const App());
}

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Home(),
    );
  }
}

// Home

import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  final List<String> colorList = <String>[];
  String randomColorName = "";
  Future<List<String>> futureColor() async {
    await Future.delayed(
      const Duration(seconds: 1),
      () {
        randomColorName = RandomColorExtension.randomColorHex();
        colorList.add(randomColorName);
        debugPrint("HexColor: $randomColorName");
        setState(() {});
      },
    );
    return colorList;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder(
        future: futureColor(),
        builder: (context, snapshot) {
          if (snapshot.data == null) {
            return const Center(
              child: CircularProgressIndicator(),
            );
          }
          return BoxGridView(
            cardColors: colorList,
          );
        },
      ),
    );
  }
}

extension RandomColorExtension on String {
  static const letters = "0123456789abcdefghijklmnopqrstuvwxyz";

  static String _randomString() {
    final Random random = Random();
    String result = '';

    for (int i = 0; i < 6; i++) {
      int randomIndex = random.nextInt(letters.length);
      result += letters[randomIndex];
    }
    return result;
  }

  static String randomColorHex() {
    String hexColor;
    do {
      hexColor = _randomString();
    } while (!RegExp(r'^[0-9a-fA-F]{6}$').hasMatch(hexColor));

    return "0xFF$hexColor";
  }
}

class BoxGridView extends StatelessWidget {
  final List<String> cardColors;
  const BoxGridView({super.key, required this.cardColors});

  @override
  Widget build(BuildContext context) {
    return GridView.builder(
      gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
        crossAxisSpacing: 10.0,
        mainAxisSpacing: 10.0,
      ),
      itemCount: cardColors.length,
      itemBuilder: (context, index) {
        return Card(
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(15.0),
          ),
          elevation: 8,
          color: Color(int.parse(cardColors[index])),
          child: Center(
            child: SelectableText(
              cardColors[index],
              cursorColor: Colors.blue,
              contextMenuBuilder: (context, editableTextState) {
                return AdaptiveTextSelectionToolbar.buttonItems(
                  anchors: editableTextState.contextMenuAnchors,
                  buttonItems: <ContextMenuButtonItem>[
                    ContextMenuButtonItem(
                      onPressed: () {
                        editableTextState
                            .copySelection(SelectionChangedCause.toolbar);
                      },
                      type: ContextMenuButtonType.copy,
                    ),
                  ],
                );
              },
              showCursor: true,
              style: const TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
                color: Colors.white,
              ),
            ),
          ),
        );
      },
    );
  }
}
```
### Running the Color Grid App

With all the code in place, you can now run the Flutter app:

```bash
flutter run
```

The app will display a grid of cards with random colors, and new colors will be generated every second. You can also copy the hex values of the colors by long-pressing on a card, and a context menu will appear with the "Copy" option.

##[GitHub](https://github.com/ayoubzulfiqar)