0% found this document useful (0 votes)
962 views142 pages

214 Implementing Dark Mode On Ios

Uploaded by

evilbinary86
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
962 views142 pages

214 Implementing Dark Mode On Ios

Uploaded by

evilbinary86
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 142

#WWDC19

Implementing Dark Mode in iOS

Kurt Revis, UIKit Engineer


Tyler Fox, UIKit Engineer

© 2019 Apple Inc. All rights reserved. Redistribution or public display not permitted without written permission from Apple.

Dark Mode is a new look


It’s easy to implement


Flexible and powerful


Dark Mode is a new look


It’s easy to implement


Flexible and powerful


RGB: 0 0 0

RGB: 239 239 244

RGB: 0 122 255


RGB: 255 255 255

RGB: 0 0 0

RGB: 10 132 255


label

systemGroupedBackground

systemBlue
label

systemGroupedBackground

systemBlue
systemBackground
systemBackground

secondarySystemBackground

tertiarySystemBackground
Primary Primary
Secondary Secondary
Tertiary Tertiary
Quaternary Quaternary
Title Title
Subtitle Subtitle
Placeholder Placeholder
Disabled Disabled
Designing for Dark Mode

Use UIKit colors, materials, views, and controls

Customize colors and images when necessary


Dark Mode is a new look


It’s easy to implement


Flexible and powerful


Implementing Dark Mode

Using iOS 13 SDK implies Dark Mode support

You decide your app’s appearance


Use Dynamic Colors

Color white
Use Dynamic Colors NEW

light white

Color

white
dark black

Demo
UIBlurEffect
style = .systemMaterial
UIBlurEffect
UIVisualEffectView
style = .systemMaterial
UIBlurEffect
UIVisualEffectView
style = .systemMaterial
UIBlurEffect
UIVisualEffectView
style = .systemMaterial
UIBlurEffect
UIVisualEffectView
style = .systemMaterial

UIVibrancyEffect
style = .fill
UIBlurEffect
UIVisualEffectView
style = .systemMaterial

UIVibrancyEffect
UIVisualEffectView
style = .fill
UIBlurEffect
UIVisualEffectView
style = .systemMaterial

contentView

UIVibrancyEffect
UIVisualEffectView
style = .fill
UIBlurEffect
UIVisualEffectView
style = .systemMaterial

contentView

UIVibrancyEffect
UIVisualEffectView
style = .fill

contentView
UIBlurEffect
UIVisualEffectView
style = .systemMaterial

contentView

UIVibrancyEffect
UIVisualEffectView
style = .fill

contentView

Vibrant View

Demo
systemBackground

systemBackground
elevated level

base level

Dark Mode is a new look


It’s easy to implement


Flexible and powerful


Dynamic Colors

light white

Color

dark black
UITraitCollection
userInterfaceIdiom .phone
userInterfaceStyle .dark
userInterfaceLevel .base
Resolving Dynamic Colors

UITraitCollection
userInterfaceStyle .dark

Dynamic Color black


Resolving Dynamic Colors NEW

let dynamicColor = UIColor.systemBackground


let traitCollection = view.traitCollection
let resolvedColor = dynamicColor.resolvedColor(with: traitCollection)
Resolving Dynamic Colors NEW

let dynamicColor = UIColor.systemBackground


let traitCollection = view.traitCollection
let resolvedColor = dynamicColor.resolvedColor(with: traitCollection)
Resolving Dynamic Colors NEW

let dynamicColor = UIColor.systemBackground


let traitCollection = view.traitCollection
let resolvedColor = dynamicColor.resolvedColor(with: traitCollection)
Resolving Dynamic Colors NEW

let dynamicColor = UIColor.systemBackground


let traitCollection = view.traitCollection
let resolvedColor = dynamicColor.resolvedColor(with: traitCollection)
Custom Dynamic Colors NEW

let dynamicColor = UIColor { (traitCollection: UITraitCollection) -> UIColor in


if traitCollection.userInterfaceStyle == .dark {
return .black
} else {
return .white
}
}
Custom Dynamic Colors NEW

let dynamicColor = UIColor { (traitCollection: UITraitCollection) -> UIColor in


if traitCollection.userInterfaceStyle == .dark {
return .black
} else {
return .white
}
}
Custom Dynamic Colors NEW

let dynamicColor = UIColor { (traitCollection: UITraitCollection) -> UIColor in


if traitCollection.userInterfaceStyle == .dark {
return .black
} else {
return .white
}
}
Custom Dynamic Colors NEW

let dynamicColor = UIColor { (traitCollection: UITraitCollection) -> UIColor in


if traitCollection.userInterfaceStyle == .dark {
return .black
} else {
return .white
}
}
Color RGB 0 0 0
UITraitCollection.current

UITraitCollection
userInterfaceStyle .dark

Dynamic Color RGB 0 0 0


Current Trait Collection

class BackgroundView: UIView {


override func draw(_ rect: CGRect) {

UIColor.systemBackground.setFill()
UIRectFill(rect)
}
}
Current Trait Collection

class BackgroundView: UIView {


override func draw(_ rect: CGRect) {

UIColor.systemBackground.setFill()
UIRectFill(rect)
}
}
Current Trait Collection

class BackgroundView: UIView {


override func draw(_ rect: CGRect) {
// UIKit sets UITraitCollection.current to self.traitCollection
UIColor.systemBackground.setFill()
UIRectFill(rect)
}
}
Current Trait Collection

class BackgroundView: UIView {


override func draw(_ rect: CGRect) {
// UIKit sets UITraitCollection.current to self.traitCollection
UIColor.systemBackground.setFill()
UIRectFill(rect)
}
}
Current Trait Collection

class BackgroundView: UIView {


override func draw(_ rect: CGRect) {
// UIKit sets UITraitCollection.current to self.traitCollection
UIColor.systemBackground.setFill()
UIRectFill(rect)
}
}
Current Trait Collection

class BackgroundView: UIView {


override func draw(_ rect: CGRect) {
// UIKit sets UITraitCollection.current to self.traitCollection
UIColor.systemBackground.setFill()
UIRectFill(rect)
}
}
Current Trait Collection

UIView UIViewController UIPresentationController


draw()
Current Trait Collection

UIView UIViewController UIPresentationController


draw()

layoutSubviews() viewWillLayoutSubviews() containerViewWillLayoutSubviews()


viewDidLayoutSubviews() containerViewDidLayoutSubviews()
Current Trait Collection

UIView UIViewController UIPresentationController


draw()

layoutSubviews() viewWillLayoutSubviews() containerViewWillLayoutSubviews()


viewDidLayoutSubviews() containerViewDidLayoutSubviews()

traitCollectionDidChange() traitCollectionDidChange() traitCollectionDidChange()


tintColorDidChange()
let layer = CALayer()

layer.borderColor = UIColor.label.cgColor
let layer = CALayer()
let traitCollection = view.traitCollection

layer.borderColor = UIColor.label.cgColor
let layer = CALayer()
let traitCollection = view.traitCollection

layer.borderColor = UIColor.label.cgColor
let layer = CALayer()
let traitCollection = view.traitCollection

// Option 1

let resolvedColor = UIColor.label.resolvedColor(with: traitCollection)


layer.borderColor = resolvedColor.cgColor
let layer = CALayer()
let traitCollection = view.traitCollection

// Option 1

let resolvedColor = UIColor.label.resolvedColor(with: traitCollection)


layer.borderColor = resolvedColor.cgColor
let layer = CALayer()
let traitCollection = view.traitCollection

// Option 2

traitCollection.performAsCurrent {
layer.borderColor = UIColor.label.cgColor
}
let layer = CALayer()
let traitCollection = view.traitCollection

// Option 2

traitCollection.performAsCurrent {
layer.borderColor = UIColor.label.cgColor
}
let layer = CALayer()
let traitCollection = view.traitCollection

// Option 3

UITraitCollection.current = traitCollection
layer.borderColor = UIColor.label.cgColor
let layer = CALayer()
let traitCollection = view.traitCollection

// Option 3

UITraitCollection.current = traitCollection
layer.borderColor = UIColor.label.cgColor
let layer = CALayer()
let traitCollection = view.traitCollection

// Option 3

let savedTraitCollection = UITraitCollection.current

UITraitCollection.current = traitCollection
layer.borderColor = UIColor.label.cgColor

UITraitCollection.current = savedTraitCollection
let layer = CALayer()
let traitCollection = view.traitCollection

// Option 3

let savedTraitCollection = UITraitCollection.current

UITraitCollection.current = traitCollection
layer.borderColor = UIColor.label.cgColor

UITraitCollection.current = savedTraitCollection
When Dynamic Color Might Change

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {


super.traitCollectionDidChange(previousTraitCollection)

}
When Dynamic Color Might Change

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {


super.traitCollectionDidChange(previousTraitCollection)

}
When Dynamic Color Might Change NEW

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {


super.traitCollectionDidChange(previousTraitCollection)

if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
// Resolve dynamic colors again
}
}
When Dynamic Color Might Change NEW

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {


super.traitCollectionDidChange(previousTraitCollection)

if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) {
// Resolve dynamic colors again
}
}
Dynamic Images
Dynamic Images

UIImageView

UITraitCollection
userInterfaceStyle .dark
Dynamic Images

UIImageView

UITraitCollection
userInterfaceStyle .dark
Resolving Dynamic Images

let image = UIImage(named: "HeaderImage")


let asset = image?.imageAsset
let resolvedImage = asset?.image(with: traitCollection)
Resolving Dynamic Images

let image = UIImage(named: "HeaderImage")


let asset = image?.imageAsset
let resolvedImage = asset?.image(with: traitCollection)
Resolving Dynamic Images

let image = UIImage(named: "HeaderImage")


let asset = image?.imageAsset
let resolvedImage = asset?.image(with: traitCollection)
Resolving Dynamic Images

let image = UIImage(named: "HeaderImage")


let asset = image?.imageAsset
let resolvedImage = asset?.image(with: traitCollection)

Trait Collections
UIScreen
UIScreen

UIWindowScene
UIScreen

UIWindowScene
UIScreen

UIWindowScene

UIWindow
UIScreen

UIWindowScene

UIWindow
UIScreen

UIWindowScene

UIWindow

UIPresentationController
UIScreen

UIWindowScene

UIWindow

UIPresentationController
UIScreen

UIWindowScene

UIWindow

UIPresentationController

UIViewController
UIScreen

UIWindowScene

UIWindow

UIPresentationController

UIViewController
UIScreen

UIWindowScene

UIWindow

UIPresentationController

UIViewController
UIScreen

UIWindowScene

UIWindow

UIPresentationController

UIViewController
UIScreen

UIWindowScene

UIWindow

UIPresentationController

UIViewController

UIView
UIScreen

UIWindowScene

UIWindow

UIPresentationController

UIViewController

UIView
UIScreen

UIWindowScene

UIWindow

UIPresentationController

UIViewController

UIView
UIScreen

UIWindowScene

UIWindow

UIPresentationController

UIViewController

UIView
UIViewController

UIView
UIViewController

UIView
UIViewController

UIView
let view = UIView()
let view = UIView()
let view = UIView()

traitCollection
let view = UIView()

traitCollection
addSubview(view)
addSubview(view)
Trait Collection Changes in iOS 13 NEW

Traits are predicted during initialization

traitCollectionDidChange(_:) called only for changes


Trait Collection Changes in iOS 13 NEW

Enable debug logging with launch argument


-UITraitCollectionChangeLoggingEnabled YES
Using Trait Collections

Layout is the best time to use traits


UIViewController.viewWillLayoutSubviews()

UIView.layoutSubviews()

UIViewController.viewDidLayoutSubviews()
!86
!86
UIScreen

UIWindowScene

UIWindow

UIPresentationController

UIViewController

UIView
light UIScreen

light UIWindowScene

light UIWindow

light UIPresentationController

light
UIViewController

light light

light light
UIView

light light
light UIScreen

light UIWindowScene

light UIWindow

light UIPresentationController

light
UIViewController

light dark

light dark
UIView

dark dark
Overriding User Interface Style NEW

class UIViewController {
var overrideUserInterfaceStyle: UIUserInterfaceStyle
}

class UIView {
var overrideUserInterfaceStyle: UIUserInterfaceStyle
}
Overriding User Interface Style NEW

class UIViewController {
var overrideUserInterfaceStyle: UIUserInterfaceStyle
}

class UIView {
var overrideUserInterfaceStyle: UIUserInterfaceStyle
}

For entire app, set Info.plist key UIUserInterfaceStyle to Light or Dark


Overriding Traits

Existing API to override any traits

class UIPresentationController {
var overrideTraitCollection: UITraitCollection?
}

class UIViewController {
func setOverrideTraitCollection(_: UITraitCollection?, forChild: UIViewController)
}

Only specify values for traits you want to override


Dark Mode API Updates


Status Bar
Before iOS 13

.default .lightContent
Status Bar NEW
iOS 13

.default

.lightContent
Status Bar NEW
iOS 13

.default
light dark

.darkContent .lightContent
UIActivityIndicatorView
Deprecated styles

.gray .white .whiteLarge


UIActivityIndicatorView NEW

New dynamic styles .medium and .large

Use the color property to set your own


Drawing Text

UILabel

UITextField

UITextView
Drawing Attributed Text

let attributes: [NSAttributedString.Key: Any] = [


.font: UIFont.systemFont(ofSize: 36.0)
]
Drawing Attributed Text

let attributes: [NSAttributedString.Key: Any] = [


.font: UIFont.systemFont(ofSize: 36.0)
.foregroundColor: UIColor.label
]
Drawing Attributed Text

let attributes: [NSAttributedString.Key: Any] = [


.font: UIFont.systemFont(ofSize: 36.0)
.foregroundColor: UIColor.label
]
Web Content

Must opt in to dark mode

Declare supported color schemes with color-scheme

Use prefers-color-scheme media query for custom colors and images

Supporting Dark Mode in Web Content WWDC 2019


tvOS

Apps built using tvOS 13 SDK are expected to support dark mode

Most new API is available


iPad Apps for Mac

Same API

Follows system setting

Matches AppKit colors and materials


Apps on iOS 13 are expected to support dark mode


Apps on iOS 13 are expected to support dark mode


Use system colors and materials


Apps on iOS 13 are expected to support dark mode


Use system colors and materials


Create your own dynamic colors and images


Apps on iOS 13 are expected to support dark mode


Use system colors and materials


Create your own dynamic colors and images


Leverage flexible infrastructure


More Information
developer.apple.com/wwdc19/214

You might also like