Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Color Me Surprised! Architecting a Robust Color System in Swift

Color Me Surprised! Architecting a Robust Color System in Swift

More companies than ever are redesigning their apps to appeal to vibrant, growing audiences. In this talk, we'll discuss strategies for architecting a robust color system capable of scaling to projects of all sizes. We'll walk through how these approaches can be utilized to rapidly iterate on design decisions and may be adapted to modify color palette themes at runtime. We'll conclude with a demonstration of how these skills can be extended to aid those with color vision concerns using the exciting new color filter accessibility features introduced in iOS 10.

Presented at try! Swift Tokyo 2017 🐣

lauraragone

March 03, 2017
Tweet

More Decks by lauraragone

Other Decks in Technology

Transcript

  1. try! Swift Tokyo Laura Ragone Color Me Surprised! Architecting a

    Robust Color System in Swift
  2. • 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
  3. Why build a color system?

  4. 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
  5. – You, probably “But my company isn’t rebranding!”

  6. • 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
  7. try! Swift Tokyo Laura Ragone “Great service but terrible mobile

    app. Everything is too colorful. Get new developers and then start again from scratch.”
  8. Design Decisions

  9. Two options to define colors: • Interface Builder • Programmatic

    Design Decisions try! Swift Tokyo Laura Ragone
  10. 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/
  11. 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
  12. 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
  13. • 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
  14. 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.
  15. • 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 }
  16. UIColor Extension Etiquette try! Swift Tokyo Laura Ragone

  17. try! Swift Tokyo Laura Ragone • Text • Primary •

    Secondary • Tertiary • Background • Content • Collection RESPONSIBILITIES UIColor Extension Etiquette • Feedback • Success • Attention • Failure • Button • Normal • Highlighted • Disabled
  18. 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
  19. Integrating Themes

  20. • 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
  21. • 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
  22. /// 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
  23. • 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
  24. /// 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
  25. // 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
  26. // 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 ✨
  27. // 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
  28. • 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 } } // . . . }
  29. • 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) // . . . } }
  30. Inclusive Design

  31. 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
  32. 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
  33. • Left: Normal Image • Right: Green/Red Filter (Deuteranopia) Inclusive

    Design: Display Accommodations try! Swift Tokyo Laura Ragone Normal Filter
  34. • 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
  35. Inclusive Design: Display Accommodations try! Swift Tokyo Laura Ragone Normal

    Simulated Simulated / Filter
  36. 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
  37. • 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
  38. Summary

  39. • 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
  40. • 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
  41. Thanks!

  42. None