How to change the app’s theme at runtime using the BLoC pattern in Flutter.
There are many cases where you might want to support multiple themes in your application, and let the user change them dynamically. Let me explain you how to do it in this tutorial using the “business logic component” pattern, also known as BLoC.
TL;DR; For those just interested in the code, here’s the code covered in this article: https://github.com/jorgecoca/theme_switcher/tree/theme-switcher-tutorial-1
We are going to build a Flutter application that consists of:
MaterialAppat the root of our app
- Two pages: the
BLoCcomponent that will receive a selected theme, and will emit a
Let’s start by creating an app named
theme_switcher, replacing the contents of
main.dart and creating
home_page.dart file that will represent the “initial” screen of our app.
We have just created a simple app with, based on
MaterialApp, with an
Text centered and a
FloatingButton. Should look like this:
Our next step will be to open the
ThemeSelectorPage from the icon that we added on the
AppBar. To do that, let’s create a
theme_selector_page.dart, and let’s modify our
HomePage to open it when pressing on the
Now our application looks like this:
As you can see, our buttons still do nothing. So the next step is to add functionality to those buttons. In order to that, we are going to create a new file that we will name
themes.dart. This file will have two missions:
- Listen to the button events, so when we receive an event we can emit a
ThemeDataobject containing the specs for the selected theme.
To accomplish this, we will make use of
Sink. You can think of
Sink as an asynchronous input to your BLoC, and
Stream as the same thing, but being an output instead.
Using a little bit of
RxDart, our main mission here is to transform the selected theme name input, and transform it into a
ThemeData object. It looks something like this:
selectedTheme.distinct().map((theme) => theme.data);
distinct() here to avoid repainting the same theme again.
In order to use
RxDart, we will need to add new package to our
pubspec and update our dependencies with
With this information, our
themes.dart file will look like this:
We have defined a
DemoTheme model that will be our BLoC input, and our
ThemeBloc class has defined a
Sink to process the input, an
Stream output to emit our themes, and our initial theme.
Now we can update our
ThemeSelectorPage to link our button events with the
Sink in the BLoC:
We have added a constructor to mark our
ThemeBloc as a dependency.
Next step here is to modify our
home_page.dart files to react to the new themes emitted:
Let’s break down these changes:
ThemeSwitcherAppnow returns a
StreamBuilder, that will help us to setup the initial state of the widget, plus also it is responsible for handling the communication with the
- But why do we need to modify the
HomePage? Well, since we navigate to the
ThemeSelectorPagefrom here, it is just a mere pass through for the
ThemeBlocobject. If we were creating two instances of
ThemeBloc, we might be emitting events in one object and listening for themes on a different one. There are better ways to do this, as I will explain on following posts, but this works for now.
With all these pieces together, we can test our theme switcher:
Hurray!!! Our application works!!! However, there are still a few details that we can improve:
- In order to use the same instance of
ThemeBloc, we modified
HomePagebecause it was the nexus between our
- We did not write any tests! And this, “mi amigo”, it is unacceptable!
We will improve these two cases in following articles ;)
I hope you enjoyed this tutorial as much as I did!