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

Making your iOS application accessible

Making your iOS application accessible

Author: Nikita Kirichek ( https://www.facebook.com/nikita.kirichek )

Доклад включает в себя:
- Как быстро сделать существующее приложение для iOS доступным для всех.
- Тестированию приложений на соответствие Apple Accessibility Guidelines
- Инструменты UIKit для обеспечения accessibility.
- Короткая демонстрация того, как всего несколько строк кода предоставят возможность использования вашего приложения для людей с инвалидностью

This talk was made for CocoaHeads Kyiv #14 which took place Oct 6 2018.

Db84cf61fdada06b63f43f310b68b462?s=128

CocoaHeads Ukraine

October 06, 2018
Tweet

More Decks by CocoaHeads Ukraine

Other Decks in Programming

Transcript

  1. Making your iOS application accessible Mykyta Kyrychek, Software developer

  2. Agenda • Common accessibility issues of mobile apps • How

    can these issues be solved? • Auditing the app to detect any accessibility issues • Using the Accessibility API to enhance user experience for a person with disability
  3. Agenda • Common accessibility issues of mobile apps • How

    can these issues be solved? • Auditing the app to detect any accessibility issues • Using the Accessibility API to enhance user experience for a person with disability
  4. Agenda • Common accessibility issues of mobile apps • How

    can these issues be solved? • Auditing the app to detect any accessibility issues • Using the Accessibility API to enhance user experience for a person with disability
  5. Agenda • Common accessibility issues of mobile apps • How

    can these issues be solved? • Auditing the app to detect any accessibility issues • Using the Accessibility API to enhance user experience for a person with disability
  6. Agenda • Common accessibility issues of mobile apps • How

    can these issues be solved? • Auditing the app to detect any accessibility issues • Using the Accessibility API to enhance user experience for a person with disability
  7. What issues people with disabilities may face when they use

    our apps?
  8. Types of disabilities Hearing Motor Skills Learning Vision

  9. Hearing Motor Skills Learning Vision

  10. None
  11. Hearing Motor Skills Learning Vision

  12. Hearing Motor Skills Learning Vision

  13. Hearing Motor Skills Learning Vision

  14. None
  15. Hearing Motor Skills Learning Vision

  16. 1 of every 7 people on Earth has a disability

  17. Solution

  18. Voice Over

  19. Interacting with Voice Over • Gestures • Switch Control

  20. None
  21. Voice Over may already work in you app

  22. Voice Over: Step by Step Guide

  23. Unlock your iPhone

  24. Tap on element

  25. Navigation: swipe

  26. Turn page: 3 fingers swipe

  27. Action: Double Tap

  28. 1. Search, heading 2. App Store, search field, double tap

    to edit 3. Trending, heading 4. merge plane, button, double tap to open 5. … 6. whatsapp, button, double tap to open 7. Today, tab, 1 of 5 8. … 9. Selected, search, 5 of 5
  29. Hearing Motor Skills Learning Vision

  30. How can I make my app accessible?

  31. Testing & Audit

  32. Testing & Audit • Turn voice over on and try

    to use your app • Inspector Audit • Switch off display brightness and check flow
  33. None
  34. None
  35. None
  36. None
  37. Testing & Audit • Turn voice over on and try

    to use your app • Inspector Audit • Switch off display brightness and check flow
  38. Inspector Audit

  39. Inspector Audit

  40. None
  41. Testing & Audit • Turn voice over on and try

    to use your app • Inspector Audit • Switch off display brightness and check flow
  42. Testing & Audit • Turn voice over on and try

    to use your app • Inspector Audit • Switch off display brightness and check flow
  43. Demo with BabyOwl app

  44. Accessibility Audit Results • Cell description • Interacting with rating

    • Button description • Speed, strength, endurance • Recommendation • Slider
  45. None
  46. Let’s make it accessible!

  47. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  48. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  49. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  50. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  51. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  52. Do I serve a purpose?

  53. Do I serve a purpose? open var isAccessibilityElement: Bool

  54. Do I serve a purpose? open var isAccessibilityElement: Bool isAccessibilityElement

    = true
  55. What is my name?

  56. What is my name? open var accessibilityLabel: String?

  57. What is my name? open var accessibilityLabel: String? accessibilityLabel =

    "Love"
  58. What is my name? open var accessibilityLabel: String? accessibilityLabel =

    "Love" accessibilityLabel = “Love Button”
  59. What’s my personality?

  60. What’s my personality? open var accessibilityTraits: UIAccessibilityTraits

  61. What’s my personality? open var accessibilityTraits: UIAccessibilityTraits accessibilityTraits = .button

  62. What’s my value?

  63. What’s my value? open var accessibilityValue: String?

  64. What will be the result of action?

  65. open var accessibilityHint: String? What will be the result of

    action?
  66. open var accessibilityHint: String? accessibilityHint = "Loves displayed owl" What

    will be the result of action?
  67. Where I am? open var accessibilityFrame: CGRect

  68. barButton?.isAccessibilityElement = true barButton?.accessibilityLabel = loved ? "Dislike" : “Love"

    barButton?.accessibilityTraits = .button barButton?.accessibilityHint = loved ? "Dislikes current owl" : "Loves current owl"
  69. barButton?.isAccessibilityElement = true barButton?.accessibilityLabel = loved ? "Dislike" : “Love"

    barButton?.accessibilityTraits = .button barButton?.accessibilityHint = loved ? "Dislikes current owl" : "Loves current owl"
  70. barButton?.accessibilityLabel = loved ? "Dislike" : “Love" barButton?.accessibilityHint = loved

    ? "Dislikes current owl" : "Loves current owl"
  71. None
  72. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  73. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  74. None
  75. isAccessibilityElement = true accessibilityLabel = "Cute rating" accessibilityHint = "Rates

    from 1 to 5" accessibilityTraits = .adjustable override var accessibilityValue: String? { set {} get { return "\(currentPinguis) pingui" } } override func accessibilityIncrement() { currentPinguis += 1 } override func accessibilityDecrement() { currentPinguis -= 1 }
  76. isAccessibilityElement = true accessibilityLabel = "Cute rating" accessibilityHint = "Rates

    from 1 to 5" accessibilityTraits = .adjustable override var accessibilityValue: String? { set {} get { return "\(currentPinguis) pingui" } } override func accessibilityIncrement() { currentPinguis += 1 } override func accessibilityDecrement() { currentPinguis -= 1 }
  77. isAccessibilityElement = true accessibilityLabel = "Cute rating" accessibilityHint = "Rates

    from 1 to 5" accessibilityTraits = .adjustable override var accessibilityValue: String? { set {} get { return "\(currentPinguis) pingui" } } override func accessibilityIncrement() { currentPinguis += 1 } override func accessibilityDecrement() { currentPinguis -= 1 }
  78. isAccessibilityElement = true accessibilityLabel = "Cute rating" accessibilityHint = "Rates

    from 1 to 5" accessibilityTraits = .adjustable override var accessibilityValue: String? { set {} get { return "\(currentPinguis) pingui" } } override func accessibilityIncrement() { currentPinguis += 1 } override func accessibilityDecrement() { currentPinguis -= 1 }
  79. isAccessibilityElement = true accessibilityLabel = "Cute rating" accessibilityHint = "Rates

    from 1 to 5" accessibilityTraits = .adjustable override var accessibilityValue: String? { set {} get { return "\(currentPinguis) pingui" } } override func accessibilityIncrement() { currentPinguis += 1 } override func accessibilityDecrement() { currentPinguis -= 1 }
  80. isAccessibilityElement = true accessibilityLabel = "Cute rating" accessibilityHint = "Rates

    from 1 to 5" accessibilityTraits = .adjustable override var accessibilityValue: String? { set {} get { return "\(currentPinguis) pingui" } } override func accessibilityIncrement() { currentPinguis += 1 } override func accessibilityDecrement() { currentPinguis -= 1 }
  81. None
  82. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  83. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  84. @available(iOS 3.0, *) open class UIAccessibilityElement : NSObject { public

    init(accessibilityContainer container: Any) unowned(unsafe) open var accessibilityContainer: AnyObject? open var isAccessibilityElement: Bool open var accessibilityLabel: String? open var accessibilityHint: String? open var accessibilityValue: String? open var accessibilityFrame: CGRect open var accessibilityTraits: UIAccessibilityTraits }
  85. let acessibiltyElement = UIAccessibilityElement(accessibilityContainer: view) acessibiltyElement.accessibilityLabel = text let frame

    = leftView.frame.union(rightView.frame) let screenFrame = UIAccessibility.convertToScreenCoordinates(frame, in: view) acessibiltyElement.accessibilityFrame = screenFrame acessibiltyElement.accessibilityTraits = .staticText view.accessibilityElements?.append(acessibiltyElement)
  86. let acessibiltyElement = UIAccessibilityElement(accessibilityContainer: view) acessibiltyElement.accessibilityLabel = text let frame

    = leftView.frame.union(rightView.frame) let screenFrame = UIAccessibility.convertToScreenCoordinates(frame, in: view) acessibiltyElement.accessibilityFrame = screenFrame acessibiltyElement.accessibilityTraits = .staticText view.accessibilityElements?.append(acessibiltyElement)
  87. let acessibiltyElement = UIAccessibilityElement(accessibilityContainer: view) acessibiltyElement.accessibilityLabel = text let frame

    = leftView.frame.union(rightView.frame) let screenFrame = UIAccessibility.convertToScreenCoordinates(frame, in: view) acessibiltyElement.accessibilityFrame = screenFrame acessibiltyElement.accessibilityTraits = .staticText view.accessibilityElements?.append(acessibiltyElement)
  88. let acessibiltyElement = UIAccessibilityElement(accessibilityContainer: view) acessibiltyElement.accessibilityLabel = text let frame

    = leftView.frame.union(rightView.frame) let screenFrame = UIAccessibility.convertToScreenCoordinates(frame, in: view) acessibiltyElement.accessibilityFrame = screenFrame acessibiltyElement.accessibilityTraits = .staticText view.accessibilityElements?.append(acessibiltyElement)
  89. let acessibiltyElement = UIAccessibilityElement(accessibilityContainer: view) acessibiltyElement.accessibilityLabel = text let frame

    = leftView.frame.union(rightView.frame) let screenFrame = UIAccessibility.convertToScreenCoordinates(frame, in: view) acessibiltyElement.accessibilityFrame = screenFrame acessibiltyElement.accessibilityTraits = .staticText view.accessibilityElements?.append(acessibiltyElement)
  90. let acessibiltyElement = UIAccessibilityElement(accessibilityContainer: view) acessibiltyElement.accessibilityLabel = text let frame

    = leftView.frame.union(rightView.frame) let screenFrame = UIAccessibility.convertToScreenCoordinates(frame, in: view) acessibiltyElement.accessibilityFrame = screenFrame acessibiltyElement.accessibilityTraits = .staticText view.accessibilityElements?.append(acessibiltyElement)
  91. let acessibiltyElement = UIAccessibilityElement(accessibilityContainer: view) acessibiltyElement.accessibilityLabel = text let frame

    = leftView.frame.union(rightView.frame) let screenFrame = UIAccessibility.convertToScreenCoordinates(frame, in: view) acessibiltyElement.accessibilityFrame = screenFrame acessibiltyElement.accessibilityTraits = .staticText view.accessibilityElements?.append(acessibiltyElement)
  92. let acessibiltyElement = UIAccessibilityElement(accessibilityContainer: view) acessibiltyElement.accessibilityLabel = text let frame

    = leftView.frame.union(rightView.frame) let screenFrame = UIAccessibility.convertToScreenCoordinates(frame, in: view) acessibiltyElement.accessibilityFrame = screenFrame acessibiltyElement.accessibilityTraits = .staticText view.accessibilityElements?.append(acessibiltyElement)
  93. None
  94. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  95. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  96. extension GraphView { override func draw(_ rect: CGRect) { addLine(from:

    startSpeedPoint, to: endSpeedPoint) addLine(from: startEdurancePoint, to: endEdurancePoint) addLine(from: startStrengthPoint, to: endStrengthPoint) let speedElement = accessibilityElement(startPoint: startSpeedPoint, endPoint: endSpeedPoint, text: "Speed \(speed) precents") let enduranceElement = accessibilityElement(startPoint: startEdurancePoint, endPoint: endEdurancePoint, text: "Endurance \(endurance) percents") let strengthElement = accessibilityElement(startPoint: startStrengthPoint, endPoint: endStrengthPoint, text: "Strength \(strength) percents") accessibilityElements = [speedElement, enduranceElement, strengthElement] } }
  97. extension GraphView { override func draw(_ rect: CGRect) { addLine(from:

    startSpeedPoint, to: endSpeedPoint) addLine(from: startEdurancePoint, to: endEdurancePoint) addLine(from: startStrengthPoint, to: endStrengthPoint) let speedElement = accessibilityElement(startPoint: startSpeedPoint, endPoint: endSpeedPoint, text: "Speed \(speed) precents") let enduranceElement = accessibilityElement(startPoint: startEdurancePoint, endPoint: endEdurancePoint, text: "Endurance \(endurance) percents") let strengthElement = accessibilityElement(startPoint: startStrengthPoint, endPoint: endStrengthPoint, text: "Strength \(strength) percents") accessibilityElements = [speedElement, enduranceElement, strengthElement] } }
  98. extension GraphView { override func draw(_ rect: CGRect) { addLine(from:

    startSpeedPoint, to: endSpeedPoint) addLine(from: startEdurancePoint, to: endEdurancePoint) addLine(from: startStrengthPoint, to: endStrengthPoint) let speedElement = accessibilityElement(startPoint: startSpeedPoint, endPoint: endSpeedPoint, text: "Speed \(speed) precents") let enduranceElement = accessibilityElement(startPoint: startSpeedPoint, endPoint: endSpeedPoint, text: "Speed \(speed) precents") let strengthElement = accessibilityElement(startPoint: startSpeedPoint, endPoint: endSpeedPoint, text: "Speed \(speed) precents") accessibilityElements = [speedElement, enduranceElement, strengthElement] } }
  99. None
  100. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  101. Bugs • Button description • Interacting with rating • Context

    for labels • Core Graphics elements
  102. Send notification UIAccessibility.post(notification: .announcement, argument: "Loved") UIAccessibility.post(notification: .screenChanged, argument: "New

    recommendation owl")
  103. None
  104. extension UIAccessibilityElement { open var isAccessibilityElement: Bool open var accessibilityLabel:

    String? open var accessibilityHint: String? open var accessibilityValue: String? open var accessibilityTraits: UIAccessibilityTraits } UIAccessibility Basic API
  105. That’s all. Not that difficult.

  106. None
  107. • Transparency and blurring • Contrast • Sizing • Motion

    • Drang & Drop Some more features we can support
  108. • Transparency and blurring • Contrast • Sizing • Motion

    • Drang & Drop Some more features we can support
  109. None
  110. extension UIAccessibilityElement { } public static var isReduceTransparencyEnabled: Bool {

    get } Transparency and blurring
  111. None
  112. if !UIAccessibility.isReduceTransparencyEnabled { let blurEffect = UIBlurEffect(style: UIBlurEffect.Style.dark) let blurEffectView

    = UIVisualEffectView(effect: blurEffect) blurEffectView.contentView.addSubview(photosRollView) rollContainerView = blurEffectView } else { rollContainerView = UIView() rollContainerView.addSubview(photosRollView) }
  113. Some more features we can support • Transparency and blurring

    • Contrast • Sizing • Motion • Drag & Drop
  114. Contrast

  115. Contrast

  116. Contrast

  117. Contrast

  118. Contrast

  119. Contrast

  120. Contrast

  121. Minimum Contrast Ratio

  122. • Minimum contrast ratio should be 4.5 : 1 •

    According to WGAG 2.0 Minimum Contrast Ratio
  123. Minimum Contrast Ratio

  124. None
  125. extension UIAccessibilityElement { } Darken Colors public static var isDarkerSystemColorsEnabled:

    Bool { get }
  126. Few more features we can support • Transparency and blurring

    • Contrast • Sizing • Motion • Drag & Drop
  127. None
  128. None
  129. None
  130. None
  131. ageLabel.font = UIFont.preferredFont(forTextStyle: .body) ageLabel.adjustsFontForContentSizeCategory = true Sizing

  132. ageLabel.font = UIFont.preferredFont(forTextStyle: .body) ageLabel.adjustsFontForContentSizeCategory = true ageLabel.font = UIFontMetrics.default.scaledFont(for:

    customFont) Custom Font
  133. But don’t forget about Layout

  134. • Transparency and blurring • Contrast • Sizing • Motion

    • Drang & Drop Some more features we can support
  135. extension UIAccessibilityElement { } Motion public static var isReduceMotionEnabled: Bool

    { get }
  136. None
  137. • Transparency and blurring • Contrast • Sizing • Motion

    • Drag & Drop Some more features we can support
  138. Drag & Drop open class UIAccessibilityLocationDescriptor : NSObject { public

    convenience init(name: String, view: UIView) public convenience init(name: String, point: CGPoint, in view: UIView) public init(attributedName: NSAttributedString, point: CGPoint, in view: UIView) weak open var view: UIView? { get } open var point: CGPoint { get } open var name: String { get } open var attributedName: NSAttributedString { get } }
  139. • Simplicity • Use Siri • Use Siri Shortcuts Few

    more words about accessibility
  140. • Simplicity • Use Siri • Use Siri Shortcuts Few

    more words about accessibility
  141. • Simplicity • Use Siri • Use Siri Shortcuts (@available

    iOS 12) Few more words about accessibility
  142. • Easier to write integration tests with KIF or UI

    Testing frameworks • Increase user base • It helps you address accessibility guidelines (508 compliance) • It’s the right thing to do Why Accessibility?
  143. • Easier to write integration tests with KIT or UI

    Testing frameworks • Increase user base • It helps you address accessibility guidelines (508 compliance) • It’s the right thing to do Why Accessibility?
  144. • Easier to write integration tests with KIT or UI

    Testing frameworks • Increase user base • It helps you address accessibility guidelines (508 compliance) • It’s the right thing to do Why Accessibility?
  145. • Easier to write integration tests with KIT or UI

    Testing frameworks • Increase user base • It helps you address accessibility guidelines (508 compliance) • It’s the right thing to do Why Accessibility?
  146. None
  147. Thanks! https://github.com/nikitakirichek https://www.facebook.com/nikita.kirichek Convenience for you is independence for me:

    https://developer.apple.com/videos/play/wwdc2017/110/ Deliver an Exceptional Accessibility Experience: https://developer.apple.com/videos/play/wwdc2018/230/