Implementing Dark Mode in iOS 13

After years of waiting and anticipation, iOS 13 finally supports native Dark Mode! Users can choose to enable a system wide dark…

Implementing Dark Mode in iOS 13

After years of waiting and anticipation, iOS 13 finally supports native Dark Mode! Users can choose to enable a system wide dark appearance that will be supported in all official apps. As we’ll see, Apple has also made it easy for developers to add dark mode support with minimal effort.

In iOS 13.0 and later, people can choose to adopt a dark system-wide appearance called Dark Mode. In Dark Mode, the system uses a darker color palette for all screens, views, menus, and controls, and it uses more vibrancy to make foreground content stand out against the darker backgrounds. Dark Mode supports all accessibility features.

Summary (iOS 13 dark mode support changes):

1. Status bar style default , darkcontent , lightcontent
2. Activity indicator — medium , large , Depreciated (gray, white, whitelarge)
3. UILabel, UITextField, UITextView — Use Semantic Colors or Custom Colors for light and dark mode
4. AttributedString — requires to provide foregroundColor
5. For Embedded web content — Declare supported color schemes with color-scheme, Use prefers-color-scheme media query for custom colors and image
6. Images — Dark mode images
7. Images Tint Color — Dark mode tint color

Designing for Dark Mode

  • Use UIKit colors, materials, views, and controls
  • Customize colors and images when necessary

People can choose Dark Mode as their default interface style, and they can use Settings to make their devices automatically switch to Dark Mode when ambient light is low.

There are three things need to take care of :

  1. Focus on your content. Dark Mode puts the focus on the content areas of your interface, allowing that content to stand out while the surrounding UI recedes into the background.
  2. Test your design in both light and dark appearances. See how your interface looks in both appearances, and adjust your designs as needed to accommodate each one. Designs that work well in one appearance might not work in the other.
  3. Ensure that your content remains comfortably legible in Dark Mode when you adjust the contrast and transparency accessibility settings.

Good news: enabling dark mode support in your app is as easy as building with the new iOS 13 SDK! When using the latest SDK, iOS will automatically update system controls such as switches, table views and buttons.

However, iOS does not automatically switch images or text colors, so you will probably notice quite a few issues with your app in dark mode.

Luckily, thanks to the numerous improvements Apple has made to asset catalogs in the past few years, most iOS apps should be able to adopt dark mode without significant code changes.

Adapting Colors

Dynamic System Colors

iOS 13 now includes new system colors in UIColor, such as a label color. By using the new system colors available in iOS 13, your app can automatically support dark mode and high contrast modes.

Don’t hard-code system color values in your app.

When specifying colors for objects in your views, it’s often easier to use the built-in semantic colors of UIColor rather than specifying our own custom colors that might not look good in both light and dark mode.

For example, when you are coloring a label, use UIColor.label, .secondaryLabel, or similar so that UIKit will automatically make sure it stands out.

mylabel.color = UIColor.secondaryLabel
Reference: https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/dark-mode/

System Colors

For backgrounds you should use UIColor.systemBackground, .secondarySystemBackground, or similar so that when you layer one view over another they don’t appear to become merged.

And when you’re using fixed colors like .red or .blue you should instead use .systemRed or .systemBlue to get a color that will adapt to the user’s trait environment – it will be a lighter red when in dark mode, and a darker red in light mode, rather than the fixed pure red of .red.

Reference: https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/dark-mode/

iOS 13 also introduces a range of six opaque gray colors you can use in rare cases where translucency doesn’t work well. For example, intersecting or overlapping elements — such as lines or bars in a grid — look better with opacity. In general, use the semantically defined system colors for UI elements.

Reference: https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/dark-mode/

Custom Colors

Although it is strongly recommended that you use system colors to automatically adapt to interface changes and ensure consistency across apps, you may want to support dark mode on custom colors.

Using iOS 13’s new asset catalog colors makes it trivial to support dark mode by adding dark versions of custom colors.

To add a dark version of asset catalog color, just select the color in the catalog, then switch Appearances to Any, Dark in the Attributes Inspector. Then, add the dark appearance version of the color.

That’s it — iOS will automatically switch to the dark version of asset catalog colors when dark mode is enabled, with no extra work from you!

Dynamic Images

Adapting Images

While most images should look fine in dark mode, especially if you are using template images which will automatically change tint if you put in the work to automatically switch colors (see Adapting Colors above), you might want some images to have a different color or look on dark mode.

Like with asset catalog colors, it’s trivial to automatically switch images in the asset catalog when dark mode is enabled. To add a dark version of any image, just select the image in the catalog, then switch Appearances to Any, Dark in the Attributes Inspector. Then, simply add the dark appearance version of the image.

Create Images for All Appearances

Make sure the images in your interface look good in both light and dark appearances. Interfaces use images in many places, including in buttons, image views, and custom views and controls. If an image is difficult to see when changing appearances, provide a new image asset that looks good in the other appearance. Better yet, use a symbol image or template image, which define only the shape to render and therefore do not require separate images for light, dark, and high-contrast environments.

Update Custom Views Using Specific Methods

When the user changes the system appearance, the system automatically asks each window and view to redraw itself. During this process, the system calls several well-known methods for both macOS and iOS, listed in the following table, to update your content. The system updates the trait environment before calling these methods, so if you make all of your appearance-sensitive changes in them, your app updates itself correctly.

Reference: https://developer.apple.com/documentation/appkit/supporting_dark_mode_in_your_interface

Trait Collection Changes in iOS 13

Enable debug logging with launch argument — UITraitCollectionChangeLoggingEnabled YES

Detecting Dark Mode Programmatically

There may be some cases in which you want to detect appearance changes programmatically and change your user interface accordingly.

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)

let hasUserInterfaceStyleChanged = previousTraitCollection.hasDifferentColorAppearance(comparedTo: traitCollection) // Bool
// Update your user interface based on the appearance
}

Overriding the User Interface Style

The system automatically opts in any app linked against the iOS 13.0 or later SDK to both light and dark appearances. If you need extra time to work on your app’s Dark Mode support or want to keep your app in a single style, you can opt out by including the UIUserInterfaceStyle key (with a value of Light or Dark) in your app’s Info.plist file. Setting this key causes the system to ignore the user’s preference and always apply the specific appearance to your app.

⚠️ Note: Supporting Dark Mode is strongly encouraged. Use the UIUserInterfaceStyle key to opt out only temporarily while you work on improvements to your app’s Dark Mode support.

Specific Screens

In iOS 13, you can now override the user interface style on specific views or view controllers. For example, you may want only a certain view controller to be in dark mode, while the rest of your app is in light mode.

To override the user interface style, just override this variable in the top view or view controller and it will propagate down to subviews:

// Inside a UIViewController override func viewDidLoad() {     super.viewDidLoad()      
// Always adopt a dark interface style. overrideUserInterfaceStyle = .dark
}