Mastering Dark and Light Themes in Flutter with BLoC: A Comprehensive Guide (with Code Examples)

Piyush Kumar
3 min readJun 20, 2023

In this article, we will explore how to implement theme switching in Flutter using the BLoC (Business Logic Component) pattern. Theming is an essential aspect of app development, allowing us to provide a visually appealing user interface. With the BLoC pattern, we can separate the theme management logic from the UI components, resulting in a cleaner and more maintainable codebase. Let’s dive into the code and learn how to build a theme switcher using BLoC.

  1. Setting Up the Project: We begin by setting up a new Flutter project and importing the necessary packages, including flutter_bloc for BLoC implementation.
  2. Creating the BLoC: Next, we create a ThemeBloc class that extends Bloc from flutter_bloc. This class will handle the theme events and emit the appropriate theme states. We define two events, toggleDark and toggleLight, to switch between dark and light themes.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

enum ThemeEvent { toggleDark, toggleLight }

class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
ThemeBloc() : super(ThemeState.lightTheme);

@override
Stream<ThemeState> mapEventToState(ThemeEvent event) async* {
switch (event) {
case ThemeEvent.toggleDark:
yield ThemeState.darkTheme;
break;
case ThemeEvent.toggleLight:
yield ThemeState.lightTheme;
break;
}
}
}

3. Defining Theme States: We define a ThemeState class that holds the ThemeData for each theme. In this example, we have darkTheme and lightTheme as static properties. Customize these theme states based on your app's requirements.

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class ThemeState {
final ThemeData themeData;

ThemeState(this.themeData);

static ThemeState get darkTheme =>
ThemeState(ThemeData.dark().copyWith(
// Customize dark theme properties
));

static ThemeState get lightTheme =>
ThemeState(ThemeData.light().copyWith(
// Customize light theme properties
));
}

4. Building the User Interface: In the main.dart file, we wrap the MaterialApp with a BlocProvider widget, providing an instance of ThemeBloc. Inside the BlocBuilder, we retrieve the current theme state and update the app's theme accordingly.

// main.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

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

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => ThemeBloc(),
child: BlocBuilder<ThemeBloc, ThemeState>(
builder: (context, state) {
return MaterialApp(
theme: state.themeData,
home: HomePage(),
);
},
),
);
}
}

5.Handling Theme Switching: In the HomePage widget, we access the ThemeBloc instance using BlocProvider.of. We display two buttons for switching between dark and light themes. On button press, we dispatch the corresponding theme event to the ThemeBloc.

// home_page.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final themeBloc = BlocProvider.of<ThemeBloc>(context);

return Scaffold(
appBar: AppBar(
title: Text('Theme Switcher'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Switch between Dark and Light Themes:',
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
onPressed: () => themeBloc.add(ThemeEvent.toggleDark),
child: Text('Dark'),
),
SizedBox(width: 10),
RaisedButton(
onPressed: () => themeBloc.add(ThemeEvent.toggleLight),
child: Text('Light'),
),
],
),
],
),
),
);
}
}

Conclusion: In this article, we explored how to implement theme switching in Flutter using the BLoC pattern. By following the code example, you can easily integrate a theme switcher into your Flutter app, providing users with the flexibility to switch between dark and light themes. The BLoC pattern allows for separation of concerns, making your codebase more maintainable and extensible. Experiment with customizing the themes and explore advanced features like persistence and dynamic theming. Happy theming with BLoC in Flutter!

--

--

Piyush Kumar

Fell in love with Flutter development. I build apps like it's my birthright.