Crafting a Theme-Toggle Flutter App: Switch Between Light and Dark Modes with Ease

Brylie Christopher Oxley - Nov 7 '23 - - Dev Community

As more users come to expect a customizable viewing experience in their apps, providing a light/dark mode toggle has become a staple in app development. Flutter, with its rich set of widgets and properties, makes this not only possible but pleasantly straightforward. In this post, we'll walk through how to add a theme toggle to your Flutter app, complete with intuitive sun and moon icons.

Let's start by setting the stage with our main function and DarkLightApp widget. We launch our app with runApp(const DarkLightApp()), which serves as the entry point. Our DarkLightApp is a StatefulWidget because theme toggling will change the app's state.

void main() {
  runApp(const DarkLightApp());
}

class DarkLightApp extends StatefulWidget {
  const DarkLightApp({super.key});
  @override
  _DarkLightAppState createState() => _DarkLightAppState();
}
Enter fullscreen mode Exit fullscreen mode

Next, we define _DarkLightAppState to hold our theme state. We initialize our theme mode to dark with ThemeMode _themeMode = ThemeMode.dark.

class _DarkLightAppState extends State<DarkLightApp> {
  ThemeMode _themeMode = ThemeMode.dark;
  ...
}
Enter fullscreen mode Exit fullscreen mode

Our _toggleTheme function takes a boolean isOn and sets the theme mode to light or dark, depending on the switch's position. This is where setState shines, notifying the framework to redraw the widget with the updated theme mode.

void _toggleTheme(bool isOn) {
  setState(() {
    _themeMode = isOn ? ThemeMode.light : ThemeMode.dark;
  });
}
Enter fullscreen mode Exit fullscreen mode

In the build method, we craft our MaterialApp, which now includes the theme toggling logic. By setting debugShowCheckedModeBanner to false, we ensure a clean UI without the debug tag.

@override
Widget build(BuildContext context) {
  return MaterialApp(
    title: 'Dark/Light App',
    debugShowCheckedModeBanner: false,
    ...
  );
}
Enter fullscreen mode Exit fullscreen mode

For our themes, we define both darkTheme and theme. The darkTheme uses Brightness.dark, while theme uses a color scheme seeded with blue for light mode.

darkTheme: ThemeData(
  brightness: Brightness.dark,
),
theme: ThemeData(
  colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
  useMaterial3: true,
),
Enter fullscreen mode Exit fullscreen mode

Now, the star of our UI: the Scaffold within MaterialApp's home. The AppBar not only holds our title but also a Row of Icons and a Switch that control the theme mode.

home: Scaffold(
  appBar: AppBar(
    title: const Text('Dark/Light App'),
    actions: [
      Icon(Icons.dark_mode),
      Switch(
        value: _themeMode == ThemeMode.light,
        onChanged: _toggleTheme,
      ),
      Icon(Icons.light_mode),
    ],
  ),
  body: const Center(
    child: Text('Hello World'),
  ),
),
Enter fullscreen mode Exit fullscreen mode

The Switch widget toggles the theme mode and, flanked by the sun (Icons.light_mode) and moon (Icons.dark_mode) icons, provides a clear visual cue for its function.

By using Flutter's ThemeData and ThemeMode, we created a seamless way to allow users to switch between light and dark themes. This not only caters to their visual preferences but also can help save battery life on OLED screens and reduce eye strain in low-light conditions.

Implementing a theme toggle in your Flutter app not only enhances the user experience but also showcases the dynamic capabilities of your app. With just a few lines of code, you can give your users the power to choose their preferred theme, making your app more inclusive and user-friendly.

Happy coding!

. . . . . . . . . . .