To start things off, make sure you install a fresh Flutter project to follow along.
// you can name the project anyway you want, // in this case I will just use this name below flutter create stacked_theme_switcher
If you aren’t familiar about the stacked architecture, then I highly recommend you to watch and learn how to setup the stacked architecture from FilledStacks before following through this tutorial since it requires an understanding of the stacked architecture.
I have learned about stacked architecture from there and the content and quality of his tutorials are great so you should check it out.
And if you are familiar about the stacked architecture, then let’s install the dependencies that we need. Head over to your
pubspec.yaml file in your project directory and put these dependencies.
dependencies: # state stacked: ^1.7.3+2 # inversion of control injectable: observable_ish: get_it: ^4.0.2 dev_dependencies: build_runner: injectable_generator:
Under dependencies, we need the stacked since it is what we are using for our state management solution. The other 3 below are the ones that handles dependency injection in our Flutter app. For
observable_ish package handles the reactive values inside services of the stacked architecture. You might say it is an old package but there is a reason why Dane from FilledStacks have chosen this package. But I am now going to talk about that in here.
And lastly, under the
dev_dependencies, these are what we need so we can avoid boilerplate code in our Flutter app since we would be using injectable annotations as how they are recognized for the builders.
Okay so make sure you run pub get to install the dependencies.
flutter pub get
After setting up for the project, we can then start writing code for our theme switcher. For the main.dart file, clean it up and leave what we only need.
We create a folder inside /lib directory and name it as “app”, in this directory is where we put our locator, this handles the dependency injection of our Flutter application. And then create a file locator.dart in it.
If you have followed then your project directory would look something like this.
You may see that VSCode have been indicating errors in the code and that’s fine because the auto-generated boilerplate code are not there yet. Hang on for a little bit as we need to create our theme switcher class or theme service.
In the /lib directory, create a new directory and name it as “services” since inside here we put all of our services that will be responsible of serving some sort of data into our viewmodels. Then create a file called as theme_service.dart and inside the file, write the code and put a lazySingleton annotation from the injectable package, so it will auto register this service and make it accessible globally in our Flutter app.
When you have created it already then it’s about time we run the builder and let it generate boilerplate code for us! Open up a terminal or use your existing terminal, then execute the command below
flutter pub run build_runner build
It would take a moment to auto generate the code for us. So please wait. :) It should look something like this if you have done things correctly.
Basically it created a locator.config.dart file and it registered the ThemeService class as a singleton, this we can now access our ThemeService globally in our application if you might need theming in other parts of the code.
This is what the auto-generated code looks like…
Right after we have set up our
ThemeService class and registered it as a singleton, we then define our theme data inside the
ThemeService class, our
ThemeService class is using a mixin
ReactiveServiceMixin since this will be handling the reactive values in the service.
We then import
observable_ish inside this
ThemeService class since we will be using it inside the class as we would be toggling over dark theme and light theme during run time. Then we also import material package since we will be using classes like
ThemeMode and other widgets related to create our theme. Then we also instantiate reactive values from
observable_ish and give it a type of
ThemeMode since we will be toggling over dark and light mode.
After defining our properties for light theme and dark theme, we can then make our application toggle between themes.
Now back into our
runApp() since we want to instantiate those services before the app starts. It should look something like this,
And then wrap our
MaterialApp() in a
ViewModelBuilder.reactive() named constructor, create a
MainViewModel class under and give the
ViewModelBuilder a type of
Here we added reference to our ThemeService that was registered as a singleton as we were setting it up. This means we have access to the methods and properties inside our ThemeService and since our MainViewModel extends ReactiveViewModel, it has a required override annotation, in it we put all of our dependencies in an array, in our case we only have _themeService in it because it is the only service we only want to listen to for changes.
If you have noticed, we have a property added in our MaterialApp widget, there we put our home screen as it’s the first view that gets rendered when our app starts.
To create this view, as convention being followed from the stack architecture, let us create a directory inside /lib and name it as “ui” and inside /ui directory we create another directory called as “views”, inside this directory is where we put all of our user interface code along with its
viewmodel of each views. And lastly, we want the home screen, so we create another folder called as “home” and inside this folder we create 2 files,
home_view.dart is where we put our UI related code and all logic inside
home_view.dart we create a Scaffold that is wrapped inside a
ViewModelBuilder of type
HomeViewModel so we have access to methods from the
ViewModel that this view is coupling with. Then as the body of our Scaffold we put a
RaisedButton widget, and on tap we toggle the theme between light and dark.
And the code for the home_viewmodel.dart …
Inside the view model is we will be using the
ThemeService again as dependency so we can make use of the
toggleTheme() method from the
ThemeService class to be able to switch between light and dark theme.
And from there, we can now toggle between dark and light theme!
Thanks for following through and I hope you have liked it. But if you have a better way of implementing this one then let me know I would appreciate it :)