App Theming in Flutter with Riverpod – Light/Dark Mode

Changing themes in mobile applications have become a popular feature nowadays. This feature not only enhances the UI of the mobile applications but also provides a good user experience.

There are two ways to change the theme (Light/dark mode) in the Flutter app. One way is to change from the default phone setting and another way is to add an option inside the app to change the theme.

In this article, we will learn about changing the theme (Light/Dark mode) of an app by using custom options with Riverpod. Riverpod is a state management library that is the rewrite of a very popular library provider.

Read more: Riverpod As An StateManagement

So, let’s begin:

Create a flutter app first.

Then Add riverpod package in pubspec.yaml file of your project.

dependencies:
  flutter:
    sdk: flutter
  flutter_riverpod: ^1.0.3

After that, wrap your entire application by ProviderScope which enables widgets to read the providers.

void main() {
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

Here, it stores the state of the providers.

Create a separate class for color schemas to declare the color of your choice for light mode and dark mode.

class AppTheme {
  ///colors for light mode
  static final lightTheme = ThemeData(
    backgroundColor: const Color(0xFF023047),
    primaryColor: const Color(0xFFF86541),
    textTheme: const TextTheme(
      headline6: TextStyle(color: Colors.white),
    ),
  );

  /// colors for dark mode
  static final darkTheme = ThemeData(
    backgroundColor: const Color(0xFF57859D),
    primaryColor: const Color(0xFFFF6E48),
    textTheme: const TextTheme(
      headline6: TextStyle(color: Colors.white),
    ),
  );
}

Now, create a separate file to declare the provider.


final changeTheme = ChangeNotifierProvider.autoDispose((ref) {
  return ChangeThemeState();
});

This will give an instance of the class ChangeThemeState will include the method to toggle the theme of an app.

class ChangeThemeState extends ChangeNotifier {
  bool darkMode = false;

  void enableDarkMode() {
    darkMode = true;
    notifyListeners();
  }

  void enableLightMode() {
    darkMode = false;
    notifyListeners();
  }
}

The class ChangeThemeState extends ChangeNotifier so that notifyListeners() can be invoked that allows updating the UI whenever the data is changed.

Here, the variable darkMode is initally false, which means the current theme of an app is light. Also, the two methods enableDarkMode and enableLightMode trigger the app to change its theme to dark and light mode respectively.

Now, update your MyApp class to listen to changeTheme provider.

class MyApp extends ConsumerWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final currentTheme = ref.watch(changeTheme);
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: AppTheme.lightTheme,
      darkTheme: AppTheme.darkTheme,
      themeMode: currentTheme.darkMode ? ThemeMode.dark : ThemeMode.light,
      home: const MyHomePage(),
    );
  }
}

MyApp is extended to ConsumerWidget to listen to the change in the provider. Then, both theme and darkTheme are provided with the custom theme. themeMode determines which theme will be used by the application if both [theme] and [darkTheme] are provided.

Create a button to change the theme.

class MyHomePage extends ConsumerWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final isDarkMode = ref.read(changeTheme).darkMode;
    final theme = Theme.of(context);
    return Scaffold(
      backgroundColor: theme.backgroundColor,
      floatingActionButton: FloatingActionButton(
        backgroundColor: theme.primaryColor,
        onPressed: () {
          if (isDarkMode) {
            ref.read(changeTheme.notifier).enableLightMode();
          } else {
            ref.read(changeTheme.notifier).enableDarkMode();
          }
        },
        child: Icon(
          isDarkMode ? Icons.dark_mode : Icons.light_mode,
        ),
      ),
    );
  }
}

Here, ref.read() is used to access the provider.

The isDarkMode gives the current theme of the app.

 final isDarkMode = ref.read(changeTheme).darkMode;

The theme changes when we press the button.

Here is our final result:

theming Flutter riverpod light/dark mode

Get the full snippet from here.