Dynamic Themes in iOS Apps

Charles Prado
The Startup
Published in
6 min readJun 24, 2020
Photo by Mario Gogh on Unsplash

Introduction

About a year ago the iOS 13 was announced at WWDC19 and one of its most anticipated features was the Dark Mode. With the introduction of this new feature a bunch of developers started to think about what was the best way to implement it making themes implementation straightforward. I was one of these developers. In this article I’ll share some of my experiences implementing dynamic themes, while also sharing my thoughts on what I think it works better for making this implementation easier and more generic.

NOTE: For more details about the implementation metionationed in this article take a look at the following repo:

“Why so Dark?”

Let’s track this from the beginning. The first conclusion I came when developing my first app that would be using dark mode is: “Why only dark mode? Why not providing the hability of the application to have not only the dark theme but any number of themes I want?”. Well, certainly that’s would be the best option for sure, but how to provide a technical solution that is generic enough for that? In the WWDC19 Apple was only talking about implementing the binary themes (light/dark). Actualy, everything was set by Apple so things works this way, the new way you have now to write the UIColor, describing the light implentation, and the dark theme implementation. Last but not least, the custom solution provided by Apple works only on iOS 13+, so that could be a problem as well. In resume, the Apple solution’s works perfeclty if you want to implement binary themes, but if you want some more dynamic you have to craft something more robust.

Colours that provides context

The first thing we have to decide before starting defining our code structure is how we gonna call our colours. In a Theme, a Colour is basically like an atom of our system. We can have dozens or even hundreads of colors in our system and the first problem I came through in mind was: “how to name all those colours? and how to keep coeherence in that naming system?”. Before having multiple themes I had colours with names like moneyGreen, infoBlue or alertRed but from now on those names started having no sense at all, I cannot call a colour somethingGreen because in a theme it can be green but for other theme it cannot be true.

So, from now on I had to start renaming my colours using context and not colours itself on its names. I mean, instead of moneyGreen I can now call this color only money. That represents the context of this colour on my system and that doesn’t change through the themes, so that could be a good name, right ?

Hm….. No!

Because, like I said I can have dozens or hundread of those colours on an app. I don’t want to be wasting time thinking on this for every colour I’m going to name. And also, I can have two colours for money, how can I name it? money1 and money2? But what’s money1 and what’s the difference from money2, it’s not very expressive, you see the problem?

I started then to think in a better way to name my colours, a way that make all my colour names very expressive and that makes that I don’t have to think a lot to define it’s name.

For my luck, there is already a colour name system that met all these requirements: The Material Design Color System.

And I know what you may be thinking right now “Hey, this guy is using Google Stuff, he’s probably an undercover enemy, closing this article right now!!111!”. Well, I promisse I’m not. Thing is, the color system used by google on Material Design is very simple and lean, with this we can have only about 20 colors for our entire application, without never having to worry in define a colour name again in life, because it covers every case we will have in our implementation. Are you not convinced? I will prove it to you!

Creating Dynamic Themes with Inheritance

public enum ColorName: String {
case colorPrimary
case colorSecondary
case colorSurface
case colorOnSurface
case colorOnSecondary
case textColorPrimary
case textColorSecondary
case textColorSecondaryVariant
case colorError
case colorOnError
case rippleOnSecondaryColor
case separatorColor
case infoColorVariant
case colorStatusBar
case colorOnPrimary
case navigationBar
case borderColor
case clear
}

Above are all the the colours I recommend you to have in your application. With only these colours you can cover every case you’ll have in your entire app, in every kind of app you are developing. The first thing you’ll notice is, only the colour names are defined in this enum, so the colours are being defined in anywhere else (we will talk about this soon). Another thing is, the last threee colours are not from Material Color System, they are included here just for convinience.

To define our themes in the most generic way possible the best option would be: setting it outside the code! In a well difunded file notation like XML, YAML, PLIST or JSON. This way you are free to fetch it from the server side if you want or even to share it with someone outside of the tech team as well. In my case I choosed to set it in a JSON file called Themes.json. This is the file where I define which theme I’m going to use in the system and every colour it uses.

For the AppThemeSample linked at the begining of this article the Themes.json files seems like this:

As you may have already noticed, I don’t only have the light and the dark theme in this Themes file, I also have a Bulbassaur, Pikachu, Charmander and Squirtle themes, each one with its own colour definitions.Also, it’s not every theme that has every colour definition on it scope, some have only one or two colours, and that’s the way we are able to have dynamic themes in a easy and fast way: we use inheritance in our themes and a recursive call for colour properties. Take a look:

A theme can always have a parent theme, that can be set on the Themes.json. If a colour, for example colorPrimary, is being called for ThemeA and it doens’t have it colour defined but its parent has, the colorPrimary returned will be the ThemeA’s parent. If the parent doens’t have the color the algorithm will search for the parent’s parent and so on. This way we make that, with only the 18 colors defined on our ColorName enum we can set any color through the entire system, without having to create new colours ever again. Because, think, if you have, for example, a cell that has a different background colour than your controller, it makes more sense to have a theme for your cell that inherit from your controller (or for another theme that makes more sense) and then you override only the background color for the cell theme instead of creating a new color name. Futhermore, you define a computed variable on the ColourName enum that will return the correct colour based on the theme you want, what makes the solution even more generic:

Cool, right? :)

Where to go from here?

The repository linked at the beginning of this article provides a complete example of how I implemented the complete idea described here, you can take I look on the the AppTheme folder for the framework implementation details or in the AppThemeSample for a example of application using this idea to implement dynamic themes. The AppTheme also implements dynamic buttons and labels definitions using JSON files (a similar idea from what was discussed here), so feel free to explore the code. The idea is to convert the AppTheme into a cocoapod library, the only prequerisite missing for that is make that the Themes enum can be set outside the AppTheme. I opened the code in that repository so you are free to add your collaboration if you want. You can also, simply drag and drop the code there to your code and that will perfectly work as a library.

So, that’s it! With this we’re done. This was the first time I was written a technical article so I hope that you have enjoied reading and that may this content have been useful in some way to you. Feel free to leave a comment if you have some doubt or any feedback :)

Happy Coding!

--

--