Switch Themes In Your App

A Work In Progress

This is part of the A Work in Progressseries of articles covering the progress of a simple ‘ToDo’ app I’m working on called WorkingMemory. The intent of this series is to document the implementation of every and all aspect of this app, its construction as well as its use of the MVC framework library package, mvc_application.

I Like Screenshots. Click For Gists.

As always, I prefer using screenshots over gists to show concepts rather than just show code in my articles. I find them easier to work with, and easier to read. However, you can click or tap on them to see the code in a gist or in Github. Ironically, it’s better to read this article about mobile development on your computer than on your phone. Besides, we mostly program on our computers and not on our phones. For now.

No Moving Pictures, No Social Media

There will be gif files in this article demonstrating aspects of the topic at hand. However, it’s said viewing such gif files is not possible when reading this article on platforms like Instagram, Facebook, etc. They may come out as static pictures or simply blank placeholder boxes. Please, be aware of this and maybe read this article on medium.com

Other Stories by Greg Perry
Switching themes in Flutter apps like a fox!

It’s A Wrapping Theme

I noted to use the DynamicTheme library package, it has to be the ‘root widget’ for the app (i.e. the first State object instantiated for the app). Implementing a library package as the ‘root widget’ has been a practice I’ve seen many times before. You see, doing so ensures the library package’s setState() function calls will then rebuild the MaterialApp widget or the CupertinoApp widget it wraps around.

main.dart

Set Your Theme

Before we look at this alternative, let’s continue with this approach so as to understand the fundamentals involved in achieving this ‘dynamic theming.’ And so, when changing the app’s theme, it all comes down to calling the MaterialApp widget or CupertinoApp widget again, but with a different value for its named parameter, theme. That means it all comes down to calling the State object’s build() function that contains that MaterialApp widget or CupertinoApp widget, and of course, that’s achieved by calling that State object’s setState() function. Follow so far?

main.dart and dynamic_theme.dart

Change Your Theme

In Ritesh Sharma’s sample code, when a user does select another theme option from the menu dropdown, the function, changeColor(), is called. It’s there where the function, DynamicTheme.of(), obtains the State object, DynamicThemeState. That State object’s setThemeData() function is then called passing in the selected ‘ThemeData’ value. This is all highlighted by the first red arrow below.

home_page.dart
dynamic_theme.dart

My Own Theme

My ‘ToDo’ app, WorkingMemory, has the same ability. It too can change its ‘theme’ with a selection from a list. It too uses the same underlying mechanism that calls, again and again, the State object’s build() function containing the MaterialApp widget or the CupertnoApp widget — depending on the running platform. Of course, this app uses the MVC framework supplied by the library package, mvc_application, and so it’s that framework that provides the means to perform such an operation.

app.dart
view.dart

Your Theme Menu

Like Sharma’s example, the WorkingMemory app has an array of color themes available in a dropdown menu. The screenshot below on the left-hand side displays the initState() function of the class, AppViewState. Note, AppView extends class, AppViewState, in this framework and so it’s all the same ‘root widget’ for the Flutter app. Below, you’re seeing the app’s menu being initialized in the State object’s initState() function. Part of its initialization is to return the app to the last selected color theme, and like Sharma’s own sample code, SharedPreferences is used to determine the last selected colour theme.

What’s Your Theme

In this WorkingMemory app, however, I incorporate the default menu dropdown offered by the framework. Doing so, you then have the standard ‘About’ option available to you as well as this cute little ‘color picker’ to change the color theme of your app. A screenshot of the Appmenu class’ init() function, reveals how the last selected color theme is reassigned to the app. We’ll take a look inside that onChange() function next.

appmenu.dart

What’s Your Preference

Preserving your preferences is such a common feature found in mobile apps, the ‘Shared Preferences’ capability is engrained in the framework. In both the function, onChange(), and the getter, colorSwatch, the library package, Prefs, is used. Like Ritesh Sharma’s sample code, Prefs works with the plugin, shared_preferences, to preserve and then retrieve the last selected colour theme. In my case, I wrote the library package, Prefs, to make working with the plugin just a little easier.

appmenu.dart

A Theme Change

When the color picker is opened and a new color picked, the function, onChange(), is called. All the magic happens in this function. A screenshot below of the function shows you the selected ColorSwatch value is merely assigned to the app’s themeData property and then the State object’s refresh() function is called. Of course, there’s a bit more going on in the underlying code, but that’s pretty much it on this side. Note, if you’re app is running in iOS, there’s a ‘Cupertino’ counterpart receiving the selected color as well. Note, the breakpoint below highlights the function, Prefs.setInt(). It’s recording the selected value in Shared Preference for the next time the app starts up.

appmenu.dart
app.dart

Options are the Theme

Again, being a framework, you’ll notice, at that breakpoint, there are two other sources for the named parameter, theme. Why? Because! That’s why. A framework must allow for other circumstances that may dictate how the app’s theme is generated from one particular Flutter app to another.

view.dart
view.dart
app.dart

Refresh Your Theme

Let’s go back to the onChange() function and examine, once the property, App.themeData, is assigned a new value, how the App’s MaterialApp widget is called again and rebuilt? Well, like Ritesh Sharma’s sample code, the setState() function for the ‘Root Widget’ is indeed called. However, this is done by the framework without the use of a ‘wrapper’ class. When the framework first starts up, ready access to the ‘root’ State object is made available right away if and when the developer needs it. Let’s show you now how that particular setState() function is called.

appmenu.dart
app.dart

A Super Refresh

It’s in the super.refresh() function where you see the setState() function being called. The refresh() function resides in the library package, mvc_pattern, which is the core component that implements in the MVC Design Pattern in Flutter. However, if you look closely at the screenshot below, you’ll realize the setState() function called also resides in this MVC library package. You can see it’s listed above the refresh() function, and it’s that function that finally calls Flutter’s own setState() function to rebuild the interface. That’s, of course, if it’s allowed to with the instance variable, _rebuildAllowed — but that’s a whole other story for another time.

mvc_pattern.dart

An App’s Refresh

Let’s now take a quick peek at the function, App.refresh(), where the breakpoint above was set to stop code execution. It’s there you readily see the framework indeed has a reference to the ‘root’ State object called, _vw. It’s this instance variable, _vw, that references the State object called, AppView.

app.dart

TL;DR

Another Bizaar Example

There’s another example I wanted to quickly review with you regarding yet another sample app called Bazaar. This app is discussed in detail in the free article, Bazaar in MVC, but here I just wanted to examine one aspect of it that also involves the ‘switching’ of its theme. In this case, it merely allows the user to change the theme from light mode to dark mode and back again.

themeChanger.dart

Refresh Your Theme

Like the past examples you’ve seen, a setState() function is then called which causes the MaterialApp() widget to be ‘rebuilt.’ Consequently, its named parameter, theme, is assigned the latest value. As you know, in this framework it’s the function, refresh(), that eventually calls the setState() function.

app.dart
BazaarApp.dart
themeChanger.dart

Refresh The State

Again, the AppView object is the ‘root’ State object for this framework. Hence, when a refresh() function is called from anywhere in the app, the AppView will call its build() function again, which calls its MaterialApp widget again and, in this case, assigns the latest theme to the App.

homeDrawer.dart

Init Your Theme

Note, being an extension of the framework’s StateMVC object, the AppView object calls its initState() function and the initState() function of all the Controller objects it may have. That’s what you see in the screenshot below on the left-hand side. The class, BaraarApp (extends AppView), has the Controller, BazaarApp, and ThemeChanger, to work with. Hence, when the State object calls the ThemeChanger’s initState() function, as you see in the screenshot below on the right-hand side, that’s where this app acquires the theme to be displayed when it starts up. Easy Peasy.

BazaarApp.dart and themeChanger.dart

Set Your Own State First

Note, calling the refresh() function means you’re calling the setState() function of the ‘current’ State object and then the setState() function of the AppView State object. It’s akin to calling the two functions in the screenshot below. Now, why would you do that you may ask? Well, I’ll demonstrate.

DECODE Flutter on YouTube

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store