Waldo sessions now support scripting! – Learn more
App Development

Flutter Enums: Defined and Explained With Examples

Juan Reyes
Juan Reyes
Flutter Enums: Defined and Explained With Examples
March 15, 2022
13
min read

In this article, we'll explore the concept of Flutter enum technology stack. By the end of this article, you'll have a basic understanding of what an enum is, how to implement an enum in Flutter, and how to bind enums to objects.

This article is aimed at Flutter developers and thus requires a basic understanding of Dart and the Flutter technology.

If you haven't explored Flutter and its development stack yet, we recommend you do so here. However, if you're only looking to understand what enums are, you can find more information on our other articles covering your technology of preference.

Let's move on.

What Is an Enum?

Before we dive into the specifics of Flutter enum, let's first explore what enums are.

Enums, or enumerated types, are a data type consisting of a set of named values called elements, members, numerals, or enumerators of the type.

In essence, an enum allows a programmer to use a custom type with a restricted set of values instead of using an integer to represent a set of values.

For example, if we use the colors of the rainbow, which are

  • red,
  • orange,
  • yellow,
  • green,
  • blue,
  • indigo, and
  • violet,

the compiler will now internally use an int to hold these. If no values are supplied, red will be 0, orange will be 1, etc.

Pretty simple, right?

Great, moving on.

Our First Flutter App

Before we jump into examples of enums in Flutter, we want to build a simple Flutter app that you can use to test the samples that we'll be demonstrating in this article.

In order to create a simple Flutter app, we'll be using the online Flutter compiler DartPad, but if you want to run your apps on your system, feel free to jump to the Flutter guide website here and make sure you have your environment set up. But, again, we'll be keeping it simple for this article and refer only to DartPad.

Now, to create your first Flutter app, all you need to do is make the skeleton for the view and state of the application. Feel free to use this one and add it to DartPad.

 
 
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}
class _MyAppState extends State {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          actions: [],
        ),
        body: Column(
          children: [
            Text("HELLO WORLD!"),
          ],
        ),
      ),
    );
  }
}

If you run this code, you'll be greeted with the following:

Notice that we just have a simple text view with the text "HELLO WORLD!" in it. For the purpose of this article, we'll be restricting our code to this structure, but feel free to play with it and modify whatever you want.

Once you feel like you understand what's going on with the view structure in this example, you can continue to the rest of the article.

Now, let's explore an example of a simple enum in Dart.

Examples of Flutter Enums

As mentioned above, an enum is used to define named constant values.

An enumerated type is declared using the keyword "enum."

Creating a Flutter Enum

Following the colors of the rainbow example, here's an enum representing the same data in Dart:

 
 
enum MyColors {
   red,
   orange,
   yellow,
   green,
   blue,
   indigo,
   violet
}

Notice that we didn't define any integer values.

In Dart, inputting these values is unnecessary since each of the symbols in the enumeration list stands for an integer value.

By default, the value of the first enumeration symbol is 0, which essentially denotes an index of the order of items in the enum.

If you want to see them in action, you can run the following code, see for yourself, and confirm if the result matches our prediction.

 
 
enum MyColors {
   red,
   orange,
   yellow,
   green,
   blue,
   indigo,
   violet
}
void main() {
  print(MyColors.values);
}
// RESULT
// [MyColors.red, MyColors.orange, MyColors.yellow, MyColors.green, MyColors.blue, MyColors.indigo, MyColors.violet]

Setting Values on a Flutter Enum

It's important to note that enums normally cannot be set to a value after compilation, as they aren't intended to be mutable.

As mentioned by one of the developers of Dart, "As of now, Dart enums are not mutable structures."

Getting Values From a Flutter Enum

However, getting values from an enum—that's another matter entirely.

All you need to do to get the value of an enum in Dart is refer to the specific property or index of the value you want.

 
 
enum MyColors {
   red,
   orange,
   yellow,
   green,
   blue,
   indigo,
   violet
}
void main() {
  print(MyColors.values);
  MyColors.values.forEach((v) => print('value: $v, index: ${v.index}'));
}
// RESULT
// [MyColors.red, MyColors.orange, MyColors.yellow, MyColors.green, MyColors.blue, MyColors.indigo, MyColors.violet]
// value: MyColors.red, index: 0
// value: MyColors.orange, index: 1
// value: MyColors.yellow, index: 2
// value: MyColors.green, index: 3
// value: MyColors.blue, index: 4
// value: MyColors.indigo, index: 5
// value: MyColors.violet, index: 6

Run the code and confirm if it's printing the colors and their index according to the expected result.

Additionally, you can add enums to class objects and use them as properties to define and retrieve values for your object instances.

A simple example would be something like the following:

 
 
enum MyColors {
   red,
   orange,
   yellow,
   green,
   blue,
   indigo,
   violet
}
class Flower {
  final String name;
  final MyColors color;
  Flower(this.name, this.color);
}
final myFlower = Flower("Rose", MyColors.blue);
void main() {
  if (myFlower.color == MyColors.blue) {
    print("That's a special flower!");
  } else {
    print("That's just a normal rose");
  }
}

Notice that you can directly check and compare the value of an enum with the definition itself without needing to refer to its index. This behavior happens because Dart is smart enough to know that each enum is a type of its own and can check them at compile and runtime.

Binding Flutter Enums

Now that we've explored the fundamentals of enums and how to represent them in Dart, let's see how we can do more complex stuff like binding an enum to a view.

For this example, we'll be binding the color enum to a DropdownButton.

If you have a DropdownButton view already set, then go to the instance where it's initialized and change it to the following:

 
 
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}
class _MyAppState extends State {
  MyColors? myColor = MyColors.red;
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          actions: [],
        ),
        body: Column(
          children: [
            DropdownButton(
                value: myColor,
                onChanged: (MyColors? newValue) {
                  setState(() {
                    myColor = newValue;
                  });
                },
                items: MyColors.values.map((MyColors color) {
                  return DropdownMenuItem(
                    value: color,
                    child: Text(color.toString()));
                }).toList()
            ),
          ],
        ),
      ),
    );
  }
}
enum MyColors {
   red,
   orange,
   yellow,
   green,
   blue,
   indigo,
   violet
}

that we set the DropdownButton type argument to be the enum type.

Running this code would give you the following result:

You can now proceed to check the dropdown and see that all the colors are available for you to select.

Extending Flutter Enums

Now, let's say you want to add some extra functionality to your enum. For example, you might want to print some custom text for each value depending on certain conditions, and doing it on each method of your application is not practical.

Well, you can easily do that by extending your enum with extra methods on Dart.

In order to extend our enum, all we need to do is use the "extension" directive and create a special class that contains the methods to add to our enum.

You can see an example of this approach right here:

 
 
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show describeEnum;
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}
class _MyAppState extends State {
  bool isRed = true;
  @override
  Widget build(BuildContext context) {
    MyColors? myColor = getRandomColor(isRed);
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          actions: [
            FlatButton(
              onPressed: () {
                setState(() {
                  isRed = !isRed;
                });
              },
              child: Text(myColor != null ? myColor.displayTitle : 'None'),
            )
          ],
        ),
        body: Column(
          children: [
            Text(() {
              switch (myColor) {
                case MyColors.red:
                  return 'The state is RED';
                case MyColors.blue:
                  return 'The state is blue';
                default:
                  return 'THERES NO STATE!';
              }
            }()),
          ],
        ),
      ),
    );
  }
}
enum MyColors {
   red,
   orange,
   yellow,
   green,
   blue,
   indigo,
   violet
}
extension ColorExtension on MyColors {
  String get name => describeEnum(this);
  String get displayTitle {
    switch (this) {
      case MyColors.red:
        return 'This is red';
      case MyColors.orange:
        return 'This is orange';
      case MyColors.yellow:
        return 'This is yellow';
      case MyColors.green:
        return 'This is green';
      case MyColors.blue:
        return 'This is blue';
      case MyColors.indigo:
        return 'This is indigo';
      case MyColors.violet:
        return 'This is violet';
      default:
        return 'MyColors is null';
    }
  }
  Color color() {
    switch (this) {
      case MyColors.red:
        return Colors.red;
      case MyColors.orange:
        return Colors.orange;
      case MyColors.yellow:
        return Colors.yellow;
      case MyColors.green:
        return Colors.green;
      case MyColors.blue:
        return Colors.blue;
      case MyColors.indigo:
        return Colors.indigo;
      case MyColors.violet:
        return Colors.purple;
      default:
        return Colors.transparent;
    }
  }
}
MyColors? getRandomColor(bool isRed) {
  switch (isRed) {
    case true:
      return MyColors.red;
    case false:
      return MyColors.blue;
    default:
      return null;
  }
}

This code would give you the following result:

Notice that we've added two methods: a displayTitle method that returns the custom string and a color method that returns the actual color object in Flutter.

Quite simple, right?

Alternative

In the process of developing applications, we might face challenges in the form of complex requirements or unforeseen limitations with APIs and hardware. When building complex systems and services with broad reach, it's essential to keep these challenges in mind while optimizing our solution to provide a robust and solid experience for our users.

Sometimes, the cost of development and time to provide that robustness and quality is too great for lean teams with limited experience and resources. In those cases, it's essential to rely on more sophisticated and reliable testing solutions like Waldo's behavioral replay engine.

Our solution can handle your app's dynamic screen, variations in load time, and other common flakiness issues to provide your team with real-time, reliable insights on your product.

You can check it out here.

Conclusion

There's a lot more that can be done to make applications that are very robust and complex. However, for most of the requirements that you might face, this is a good start.

In this post, we've learned what comprises a Flutter application, how to implement enums, and how to make the best use of all the possibilities that the platform offers you. With this knowledge, you should better be able to produce solutions that your clients will love.

Automated E2E tests for your mobile app

Waldo provides the best-in-class runtime for all your mobile testing needs.
Get true E2E testing in minutes, not months.

Reproduce, capture, and share bugs fast!

Waldo Sessions helps mobile teams reproduce bugs, while compiling detailed bug reports in real time.