Slide 1

Slide 1 text

try! Swift Tokyo Laura Ragone Color Me Surprised! Architecting a Robust Color System in Swift

Slide 2

Slide 2 text

• How to architect a basic color system • Strategies for adding custom themes • Considerations for inclusive design Today, we’ll learn… try! Swift Tokyo Laura Ragone

Slide 3

Slide 3 text

Why build a color system?

Slide 4

Slide 4 text

try! Swift Tokyo Laura Ragone Reasons to Build a Color System Access colors easily from a fixed location CONVENIENCE Ensure colors are consistent app-wide UNIFORMITY Iterate on designs with minimal effort ADAPTABILITY

Slide 5

Slide 5 text

– You, probably “But my company isn’t rebranding!”

Slide 6

Slide 6 text

• Apple’s Human Interface Guidelines change • tvOS 10 introduced Dark Mode • OLED screens are (allegedly) on the way • Pressure from reviewers on the App Store… Reasons to Build a Color System try! Swift Tokyo Laura Ragone

Slide 7

Slide 7 text

try! Swift Tokyo Laura Ragone “Great service but terrible mobile app. Everything is too colorful. Get new developers and then start again from scratch.”

Slide 8

Slide 8 text

Design Decisions

Slide 9

Slide 9 text

Two options to define colors: • Interface Builder • Programmatic Design Decisions try! Swift Tokyo Laura Ragone

Slide 10

Slide 10 text

try! Swift Tokyo Laura Ragone Design Decisions: Interface Builder • Interface Builder tools have become extremely powerful • Easy access to color picker from the utility panel • .clr files with custom palettes may be shared across teams* PROS * https://www.natashatherobot.com/xcode-color-palette/

Slide 11

Slide 11 text

try! Swift Tokyo Laura Ragone Design Decisions: Interface Builder • Colors lack a common reference once set • Changing a color app-wide involves opening and modifying many files • Unable to accommodate support for multiple themes CONS

Slide 12

Slide 12 text

try! Swift Tokyo Laura Ragone Design Decisions: Programmatic • UI elements reference a common UIColor • Ensures all views are updated appropriately • Smaller, more manageable diffs • Facilitates modifying colors at runtime PROS

Slide 13

Slide 13 text

• Store colors in a UIColor extension • Create a struct defining colors by hue • Utilities like Zeplin include color export tools that may simplify this process UIColor Extension Etiquette try! Swift Tokyo Laura Ragone

Slide 14

Slide 14 text

extension UIColor { // Mark: Nested Types struct Palette { static let ceruleanBlue = UIColor(red: 0.0 / 255.0, green: 158.0 / 255.0, blue: 220.0 / 255.0, alpha: 1.0) static let cannonPurple = UIColor(red: 147.0 / 255.0, green: 78.0 / 255.0, blue: 132.0 / 255.0, alpha: 1.0) static let mulberryRed = UIColor(red: 197.0 / 255.0, green: 81.0 / 255.0, blue: 82.0 / 255.0, alpha: 1.0) static let fireBushOrange = UIColor(red: 225.0 / 255.0, green: 148.0 / 255.0, blue: 51.0 / 255.0, alpha: 1.0) static let saffronYellow = UIColor(red: 242.0 / 255.0, green: 190.0 / 255.0, blue: 46.0 / 255.0, alpha: 1.0) static let sushiGreen = UIColor(red: 118.0 / 255.0, green: 184.0 / 255.0, blue: 59.0 / 255.0, alpha: 1.0) static let black = UIColor(white: 44.0 / 255.0, alpha: 1.0) static let white = UIColor.white } // . . . } UIColor Extension Etiquette try! Swift Tokyo Laura Ragone Note: Unless transparency is explicitly desired, specify colors using an alpha of 1.0.

Slide 15

Slide 15 text

• Identify colors by responsibility using class var or class func UIColor Extension Etiquette try! Swift Tokyo Laura Ragone /// Returns the color for displaying primary text on a light background. class var primaryText: UIColor { return Palette.black } /// Returns the color used for background content. class func contentBackground() -> UIColor { return Palette.white }

Slide 16

Slide 16 text

UIColor Extension Etiquette try! Swift Tokyo Laura Ragone

Slide 17

Slide 17 text

try! Swift Tokyo Laura Ragone • Text • Primary • Secondary • Tertiary • Background • Content • Collection RESPONSIBILITIES UIColor Extension Etiquette • Feedback • Success • Attention • Failure • Button • Normal • Highlighted • Disabled

Slide 18

Slide 18 text

try! Swift Tokyo Laura Ragone • Text Inverted • Primary • Secondary • Tertiary • Background Inverted • Content • Collection RESPONSIBILITIES UIColor Extension Etiquette • Feedback Inverted • Success • Attention • Failure • Button Inverted • Normal • Highlighted • Disabled

Slide 19

Slide 19 text

Integrating Themes

Slide 20

Slide 20 text

• Similar in execution to implementing Dynamic Type, except state is determined by the application, not the system • Broadcast changes via NotificationCenter • Handle state changes at the controller level Basic Themes try! Swift Tokyo Laura Ragone

Slide 21

Slide 21 text

• ColorUpdatable protocol • Allows types that have the need to update their colors to share a common interface • Enables changes in that interface to be reflected across the entire application Basic Themes: ColorUpdatable try! Swift Tokyo Laura Ragone

Slide 22

Slide 22 text

/// A protocol which denotes types which can update their colors. protocol ColorUpdatable { /// The theme for which to update colors. var theme: Theme { get set } /// A function that is called when colors should be updated. func updateColors(for theme: Theme) } Basic Themes: ColorUpdatable try! Swift Tokyo Laura Ragone

Slide 23

Slide 23 text

• ColorChangeObserving protocol • Contains extensions for conveniently adding and removing didChangeColorTheme notification observation • Responsible for informing a controller that it should update its views to the new theme Basic Themes: ColorChangeObserving try! Swift Tokyo Laura Ragone

Slide 24

Slide 24 text

/// A protocol for responding to `didChangeColorTheme` custom notifications. protocol ColorThemeObserving { /// Registers observance of `didChangeColorTheme` custom notifications. func addDidChangeColorThemeObserver(notificationCenter: NotificationCenter) /// Removes observance of `didChangeColorTheme` custom notifications. func removeDidChangeColorThemeObserver(notificationCenter: NotificationCenter) /// Responds to `didChangeColorTheme` custom notifications. func didChangeColorTheme(notification: Notification) } Basic Themes: ColorChangeObserving try! Swift Tokyo Laura Ragone

Slide 25

Slide 25 text

// MARK: - ColorThemeObserving private extension ColorThemeObserving { /// Returns the theme specified by the `didChangeColorTheme` notification’s `userInfo`. func theme(from notification: Notification) -> Theme? { // . . . return theme } /// Updates the colors of `ColorUpdatable`-conforming objects. func updateColors(from notification: Notification) { guard let theme = theme(from: notification) else { return } if var colorUpdatableObject = self as? ColorUpdatable, theme != colorUpdatableObject.theme { colorUpdatableObject.theme = theme colorUpdatableObject.updateColors(for: theme) } } } Basic Themes: ColorChangeObserving try! Swift Tokyo Laura Ragone

Slide 26

Slide 26 text

// MARK: - UIViewController extension UIViewController: ColorThemeObserving { @objc func didChangeColorTheme(_ notification: Notification) { updateColors(from: notification) } // . . . } Basic Themes: ColorChangeObserving try! Swift Tokyo Laura Ragone • Simply add default implementations to your controllers to spark the magic ✨

Slide 27

Slide 27 text

// MARK: - UITableViewController extension UITableViewController { @objc override func didChangeColorTheme(_ notification: Notification) { updateColors(from: notification) tableView.reloadData() } } // MARK: - UICollectionViewController extension UICollectionViewController { @objc override func didChangeColorTheme(_ notification: Notification) { updateColors(from: notification) collectionView?.reloadData() } } Basic Themes: ColorChangeObserving try! Swift Tokyo Laura Ragone

Slide 28

Slide 28 text

• Modify the UIColor extension to accommodate themes: Applying Themes: UIColor Extensions try! Swift Tokyo Laura Ragone extension UIColor { class func backgroundContent(for theme: Theme) -> UIColor { switch theme { case .light: return Palette.white case .dark: return Palette.black } } // . . . }

Slide 29

Slide 29 text

• Set the theme from the ColorUpdatable controller extension: Applying Themes: ColorUpdatable Conformance try! Swift Tokyo Laura Ragone // MARK: - ColorUpdatable extension ViewController: ColorUpdatable { func updateColors(for theme: Theme) { view.backgroundColor = .contentBackground(for: theme) childView.updateColors(for: theme) // . . . } }

Slide 30

Slide 30 text

Inclusive Design

Slide 31

Slide 31 text

Colorblindness: • Affects: • 8.0 % of men • 0.5 % of women • ~4.5 % of the worldwide population! Inclusive Design try! Swift Tokyo Laura Ragone Normal Vision Deuteranomaly Protanomoly Protanopia Deuteranopia Tritanopia Tritanomaly Achromatopsia Normal Vision Deuteranomaly Protanomoly Protanopia Deuteranopia Tritanopia Tritanomaly Achromatopsia

Slide 32

Slide 32 text

try! Swift Tokyo Laura Ragone ACCESSIBILITY Inclusive Design • iOS 10 introduced color filter accessibility feature • Settings -> General -> Accessibility -> Display Accommodations -> Color Filters • Compensates for sightedness needs at the system level

Slide 33

Slide 33 text

• Left: Normal Image • Right: Green/Red Filter (Deuteranopia) Inclusive Design: Display Accommodations try! Swift Tokyo Laura Ragone Normal Filter

Slide 34

Slide 34 text

• Visual Quality Assurance (VQA) testing could be simplified by simulating the full spectrum of sightedness considerations • Adapt the existing color system to simulate color limited vision using the open source library, Inclusive Color Inclusive Design try! Swift Tokyo Laura Ragone

Slide 35

Slide 35 text

Inclusive Design: Display Accommodations try! Swift Tokyo Laura Ragone Normal Simulated Simulated / Filter

Slide 36

Slide 36 text

import InclusiveColor extension UIColor { class func primaryText(for theme: Theme, blindnessType: InclusiveColor.BlindnessType = .normal) -> UIColor { let color: UIColor = { switch theme { case .light: return Palette.black case .dark: return Palette.white } }() return color.inclusiveColor(for: blindnessType) } } Inclusive Design try! Swift Tokyo Laura Ragone

Slide 37

Slide 37 text

• Consider monochromatic themes that use shades of a single color • Calculate the contrast ratio between text and backgrounds • Small text : 4.5 : 1 • Large text : 3 : 1 • Rely on visual indicators other than color to provide feedback Inclusive Design: Strategies try! Swift Tokyo Laura Ragone

Slide 38

Slide 38 text

Summary

Slide 39

Slide 39 text

• Architecting a robust color system with protocols! • Changing color themes at runtime • Developing an app that’s beautiful to all users Today, we discussed… try! Swift Tokyo Laura Ragone

Slide 40

Slide 40 text

• Stranger Themes - Sample Project • https://github.com/lauraragone/Stranger-Themes • Inclusive Color - Colorblindness Simulation Library • https://github.com/lauraragone/Inclusive-Color • Inclusive App Design - WWDC 2016, Session 801 • https://developer.apple.com/videos/play/wwdc2016/801/ • Contrast Ratio Calculator - Lea Verou • http://leaverou.github.io/contrast-ratio/ Additional Resources try! Swift Tokyo Laura Ragone

Slide 41

Slide 41 text

Thanks!

Slide 42

Slide 42 text

No content