TANASCHITA.COM
Articles about Swift and iOS Development by Natascha Fadeeva

Quick guide on supporting Dark Mode on iOS

Improve your app's user experience by following this Dark Mode support guide

15. October 2019 · 4 min read

Since iOS 13, users can choose between a system-wide light or dark appearance. This post provides you with a step-by-step-guide to supporting Dark Mode in your app.

If you don't want to support Dark Mode for now, you can scroll directly to the Good to know section.

Dark Mode... that's my thing.

Basics

Prior to iOS 13, a color on iOS had only one fixed value.

Now, Apple introduced so called semantic colors.

  1. Semantic colors are dynamic, that means they can have multiple values. When the user selects a different style mode, a semantic color changes it's value.
  1. Semantic colors are named after it's purpose, not after the color itself. Apple predefined a lot of semantic colors like label, systemBackground, secondarySystemBackground etc. Of course, you can also define your own semantic colors.

How does the system know what color to use?

Each view and view controller has it's own UITraitCollection where you can check the userInterfaceStyle property. It can be set to .dark, .light or unspecified.

Implementing Dark Mode

Colors

There are two possibilities how you can define and use colors in iOS: In code or via the asset catalog.

Defining colors in code

If you prefer to define your colors in code, you will need to define semantic colors instead of fixed color values to support dark mode.

I usually define all colors for a project in a struct like this:

struct Colors {
    static let error = UIColor(red: 198/255, green: 13/255, blue: 0/255, alpha: 1.0)
}

If you also have a similar centralized file where you define all your colors, supporting dark mode is really easy. All you need to do is to change the color definitions to the following:

static var error: UIColor {
    let light = UIColor(red: 198/255, green: 13/255, blue: 0/255, alpha: 1.0)
    let dark = UIColor(red: 242/255, green: 16/255, blue: 0/255, alpha: 1.0)

    guard #available(iOS 13, *) else { return light }
    return UIColor { traitCollection -> UIColor in
        return (traitCollection.userInterfaceStyle == .dark) ? dark : light
    }
}

You can call this color definition as usual from your views, e.g. errorLabel.textColor = Colors.error, the iOS system will figure out the rest for you.

You can remove the #available(iOS 13, *) line if you are not supporting iOS version prior to iOS 13.

After defining a dynamic color, when you use it in your view or view controller, you don't pass the trait collection. So how does the system know which color to use?

There is a new property on UITraitCollection called current. This property is set automatically by UIKit, so the developer don't need to worry about it.

Defining colors via asset catalog

If you prefer to define your colors via an Asset Catalog, you can configure Dark Mode there directly.

Open a color in the Asset Catalog, then select Any, Dark in Appearances of Attributes Inspector and you will be presented with a new color dark mode setting.

In code, you can use these colors as usual:

var errorColor: UIColor {
	return UIColor(named: "error")
}

Images

To add dark mode support for images, it is the same process as for colors with the Asset Catalog. Select Any, Dark in Appearances of Attributes Inspector, you then will be presented with the same interface as for colors to configure dark mode images.

Good to know

Only supporting light mode

As long as you are not supporting dark mode, set Info.plist key UIUserInterfaceStyle to Light.

This way, you can avoid unwanted appearance effects when users use your app with dark mode turned on.

Overriding user interface style for certain views

If you want a certain view or view controller always to use a certain mode, you can simply do it by overwriting it's overrideUserInterfaceStyle property.

Written by

Natascha Fadeeva
Author and creator of this site

Contact

Image Credits

Image by Randy Rodriguez from Pixabay