Dynamic theming with Flutter
Hi everyone, this is Antonello here and this is my first tech article. I decided to start blogging about my discoveries and approaches with Flutter and other dev stuff, so I hope you’ll hear more from me!
Today I’ll talk you about I’ve tackled the problem with having multiple themes in a Flutter application.
Nowadays the users expect from an app to do certain basic-not-basic things such as certain types of gestures, a swipe to refresh, a shiny UI, smooth animations, intuitive operations and that sort of stuff and, as a user, the ability to choose among different themes for an app is a big plus for me (especially for dark themes though).
Some days ago I found myself thinking about how to dynamically switch between light and dark themes within an app. Then it occurred to me that finding a more generalised way should be better, since I’d love to define different flavours of light and darkness.
This article assumes you already know about Inherited Widgets.
If you don’t know about Inherited Widget, there are some interesting articles about them, for example here or here.
Let’s start.
The roadmap: what are we going to do?
Since we are going to treat the current theme as a state of the app, we’re going to need an Inherited Widget wrapped by a Stateful Widget. Our Inherited Widget will expose the state of the Stateful Widget which is containing it.
It seems chaotic but we’ll get there.
Step 1: creating our themes
Though this might not be the optimal way of doing this for many reasons, this will do good enough for the purpose of this article.
The code is pretty straightforward. We have defined a helper class containing our three themes and an helper method to access them by a MyThemeKeys
key.
Step 2: setting up our Stateful Widget
Let’s wrap our ThemeData
inside the state of a Widget.
We’ve defined our CustomTheme
StatefulWidget, which contains the data for the currently selected theme.
We initialise the theme with an initialThemeKey
and provide a changeTheme
method that allows us to change the theme.
We need now to wrap this state inside an InheritedWidget, so that we can share our theme across the app.
This brings us to the next step.
Step 3: wrapping the state with an Inherited Widget
Nothing fancy. Just an ordinary Inherited Widget. Less than the ordinary, since you might note the absence of the classic .of
method, justified by the fact that we are not exposing our Inherited Widget directly, which is also private.
We’re going to expose the _CustomTheme
InheritedWidget through our Stateful widget, as we’ll see in a bit.
Step 4: putting it all together
We’re now going to update our Stateful Widget in order to use the Inherited Widget and to expose the theme.
We have provided two static methods to access and manipulate our data:
- The
of
method returns directly theThemeData
of the state. We’ll use this as a substitute of the classicTheme.of(context)
. - The
instanceOf
method returns theCustomThemeState
in order to call thechangeTheme
method.
The result
Here’s how our dynamic theme switching should look like:
Pretty handy, huh?
Here’s the code for this screen:
This is an ordinary Flutter screen, referencing the Theme
as the usual apps do. We could achieve this because we’ve placed the CustomTheme
to the root of our MaterialApp
this way:
Since the whole app did not have to reference anything different than the classic Theme
, we could do all of this on an already existing app. We’ll just need to define our CustomTheme
and put it on top of our existing app and that would be it, no further changes required, no nasty renaming, nothing at all.
What’s happening under the hood?
The gig is pretty simple.
- We change the theme calling
CustomTheme.instanceOf(context).changeTheme(ourThemeKey)
. - The change triggers a
setState
updating the theme with the new value inside theCustomTheme
Stateful Widget.
Due to the setState
, CustomTheme
`rebuilds. The Inherited Widget gets rebuilt as well, and since its updateShouldNotify
returns true
all the depending widgets (MaterialApp
in our case) are updated, resulting in a UI update with the new color scheme.
That’s all folks!
I hope you enjoyed the article and found it useful! You can find the full code here.
See you the next time, happy coding!