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:
Flutter SDK: Install Flutter from the official website https://flutter.dev/docs/get-started/install.
Flutter-compatible code editor: Choose your preferred code editor; Visual Studio Code with the Flutter extension is recommended.
Creating the Flutter Project
- Open your terminal or command prompt and run the following command to create a new Flutter project:
flutter create color_grid_app
- Change into the project directory:
cd color_grid_app
- 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(),
);
}
}
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.
_randomString()
: This private static method generates a random string of length 6 containing characters from the constantletters
. It uses theRandom
class to select random characters from theletters
string and concatenates them to build a 6-character string. Theletters
string includes digits (0-9) and lowercase letters (a-z), providing a pool of characters for the random string generation.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 variablehexColor
. Then, it uses ado-while
loop to keep generating a newhexColor
until it matches the pattern defined by the regular expressionr'^[0-9a-fA-F]{6}$'
. The regular expression^[0-9a-fA-F]{6}$
ensures that thehexColor
is a valid hexadecimal color code with exactly 6 characters and includes only digits (0-9) and letters (a-f, A-F). Once a validhexColor
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";
}
}
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:
final List<String> colorList = <String>[];
: This creates an empty list of strings namedcolorList
. This list will be used to store the generated random color values.String randomColorName = "";
: This initializes an empty string namedrandomColorName
. It will be used to hold the randomly generated hexadecimal color string.Future<List<String>> futureColor() async {
: This defines the functionfutureColor()
, which returns aFuture
containing a list of strings (List<String>
). Theasync
keyword indicates that this function can perform asynchronous operations usingawait
.await Future.delayed(const Duration(seconds: 1), () { ... });
: This line usesawait
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 usingRandomColorExtension.randomColorHex()
and store it inrandomColorName
.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.colorList.add(randomColorName);
: The generated color string is added to thecolorList
list.debugPrint("HexColor: $randomColorName");
: This line prints the hexadecimal color string to the debug console. It's helpful for debugging purposes.setState(() {});
: ThissetState
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 thecolorList
, this will trigger a rebuild of the widget, and the new color will be displayed in the grid.return colorList;
: Finally, the function returns thecolorList
, which will be wrapped in aFuture
. When theawait Future.delayed
completes its one-second delay, the future will complete with the updatedcolorList
.
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;
}
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,
),
),
),
);
},
);
}
}
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,
),
),
),
);
},
);
}
}
Running the Color Grid App
With all the code in place, you can now run the Flutter app:
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.
Top comments (0)