Implementing Dark Mode in Boxer for iOS

Nikola Kirev
VMware 360
Published in
3 min readFeb 24, 2020

With the introduction of iOS 13 and iPadOS 13, we now have system support for Dark Mode. Up to this point, having a dark theme for your app has been an optional feature for stylistic or other reasons, but now apps are expected to respect the user’s system preference and have Dark Mode support built in.

A dark theme can be suitable for a number of contexts and environments, however, not embracing this feature on a system level can result in an app that looks out of place and antiquated during everyday use.

Semantic Colors

To support Dark Mode, we came up with a system of colors defined by use case and not RGB values. Colors like this are now commonly referred to as semantic (or named) colors.

At VMware, we strive to have a consistent experience across the suite of VMware Workspace ONE productivity apps. We collaborated across engineering and design teams and came up with a set of generic color names based on use case and context.

It is important to note that we worked alongside our Android engineers to come up with this flexible and reusable system of color names. Yet, for the actual values behind these names, we made sure to use colors that respect each of the platform’s best practices. For example, a Primary Background color would be used in the same way on both platforms, but might be a different shade of grey for between iOS and Android.

Using this set of semantic colors brings a number of advantages, including:

  • Color consistency, not just between components and screens, but also across apps and workflows
  • A common language that can be used from design specs to implementation
  • Saved time and effort for engineering teams by defining the colors in a shared framework

Putting it Into Code

While semantic colors can be configured with the use of asset catalogs, we made a wrapper method and defined a system of colors in code. This makes it easier to manage and track changes in source control and should give us more flexibility when it comes to using dependency management tools.


static func dynamicColor(lightVariation: UIColor, darkVariation: UIColor) -> UIColor {
guard #available(iOS 13.0, *) else {
return lightVariation
}
return UIColor { traitCollection -> UIColor in
guard traitCollection.userInterfaceStyle == .dark else {
return lightVariation
}
return darkVariation
}
return lightVariation
}

Developing and Refactoring in an Agile Way

VMware Workspace ONE Boxer - our email, calendar and contacts app - has been in active development for many years and in that time, the codebase has grown and evolved. While the use of colors has been abstracted into a collection of methods and properties, it was designed around how the colors look and not around the context in which they have been used. This meant that we had to retire a lot of color definitions and reorganize the rest. As a result, not only did the app start supporting Dark Mode, but the default Light Mode became cleaner and more consistent across the different screens and components of the app.

In addition, thanks to our wrapper method for defining semantic colors, we were also able to develop Dark Mode using Xcode 11 Beta, while the rest of the team was working on other features and we were shipping app updates with Xcode 10.

We transitioned from this:

private func setupStyle() {
backgroundColor = UIColor.white
titleLabel.textColor = UIColor.black
attributesLabel.textColor = UIColor.darkGray
}

… to using semantic color definitions like this:

private func setupStyle() {
backgroundColor = UIColor.VisionColors.Backgrounds.collection
titleLabel.textColor = UIColor.VisionColors.Text.tertiary
attributesLabel.textColor = UIColor.VisionColors.Text.tertiary
}

This new code is much more future proof and easier to maintain across engineering and design.

This has been a quick look behind our process of bringing Dark Mode support to Boxer in an iterative and reusable way. I hope it gives you an idea of how you can approach a similar task in your projects.

--

--

Nikola Kirev
VMware 360

Developer & Designer. Building things from code and colors.