Dynamic theming with Flutter

Antonello Galipò
Flutter Community
Published in
4 min readApr 14, 2019

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 the ThemeData of the state. We’ll use this as a substitute of the classic Theme.of(context) .
  • The instanceOf method returns the CustomThemeState in order to call the changeTheme 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.

  1. We change the theme calling CustomTheme.instanceOf(context).changeTheme(ourThemeKey).
  2. The change triggers a setState updating the theme with the new value inside the CustomTheme 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!

--

--

Antonello Galipò
Flutter Community

Flutter and Android developer with an enormous love for Yoga and hipster habits.