DEV Community

Ayoub Ali
Ayoub Ali

Posted on

Building a Infinite Color Grid App in Flutter with Dart

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.

  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:
flutter create color_grid_app
Enter fullscreen mode Exit fullscreen mode
  1. Change into the project directory:
cd color_grid_app
Enter fullscreen mode Exit fullscreen mode
  1. Replace the content of the lib/main.dart file with the following code:
// main.dart
import 'package:flutter/material.dart';

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

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

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.


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";
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

  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;
  }
Enter fullscreen mode Exit fullscreen mode

Step - 3

Now Lets Create a Custom Grid Widget

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,
              ),
            ),
          ),
        );
      },
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Full Code

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,
              ),
            ),
          ),
        );
      },
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Running the Color Grid App

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

flutter run
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)