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

noteのiOSアプリで実装したアクセシビリティの全て #iosdc #a /a11y_with_iOS_App_on_note

fromkk
September 18, 2021

noteのiOSアプリで実装したアクセシビリティの全て #iosdc #a /a11y_with_iOS_App_on_note

iOSDC Japan 2021で登壇した資料です。

----CfP----
noteのiOSアプリはここ1年間で大きな変化を遂げました。
元々30%程度だったSwift率が90%を超え、デバイスもiPhoneの縦画面のみの対応でしたがiPadの複数ウィンドウにも対応しました。
このように目に見えるカイゼンを進めてきた私たちですが、あるきっかけで目に見えない課題があることを知りました。
アクセシビリティ機能を駆使して私たちのアプリを利用してくれている方からお問い合わせをいただいたのです。
この方の日頃の利用方法についてインタビューさせていただくことになり、今まで見えていなかった課題に気づくことができました。
そこでアクセシビリティの有識者に力を借りながら、Voice OverやDynamic Typeといったアクセシビリティの助けとなる機能にも対応をはじめました。
・Voice Overを利用するとさわれると思っているUI要素にさわれない
・わかりやすいと思っていたボタンなのにVoice Overを通すと何のボタンなのか理解ができない
このトークではこういった課題を認知して、実際に対応したことをまとめてお話します。

fromkk

September 18, 2021
Tweet

More Decks by fromkk

Other Decks in Programming

Transcript

  1. 1

    View Slide

  2. 2

    View Slide

  3. 3

    View Slide

  4. note inc.


    ೥݄ελʔτ
    4

    View Slide

  5. note inc.


    cakes͸ଟ਺ͷΫϦΤΠλʔ΍ग़൛ࣾͱఏܞ͍ͯ͠Δίϯςϯπ഑৴αΠτ
    Ͱ͢ɻಡऀͱΫϦΤΠλʔΛΑΓ਎ۙʹ݁ͼ͚ͭΔ͜ͱͰɺίϯςϯπͱͷ
    ৽͍͠ग़ձ͍ͷ৔Λఏڙ͠·͢ɻ
    5

    View Slide

  6. note inc.


    ೥݄ελʔτ
    6

    View Slide

  7. note inc.


    ΫϦΤΠλʔ͕จষ΍ը૾ɺԻ੠ɺಈըΛ౤ߘͯ͠ɺϢʔβʔ͕ͦͷίϯςϯπΛ
    ָ͠ΜͰԠԉͰ͖ΔϝσΟΞϓϥοτϑΥʔϜɻͩΕ΋͕૑࡞Λָ͠ΜͰଓ͚ΒΕ
    ΔΑ͏ɺ҆৺Ͱ͖Δงғؾ΍ɺଟ༷ੑΛେ੾ʹ͍ͯ͠·͢ɻ
    7

    View Slide

  8. note inc.


    ϛογϣϯ
    ͩΕ΋͕૑࡞Λ͸͡Ίɺ
    ଓ͚ΒΕΔΑ͏ʹ͢Δɻ
    8

    View Slide

  9. ΞΫηγϏϦςΟ
    9

    View Slide

  10. ΢ΣϒΞΫηγϏϦςΟج൫ҕһձ

    https://waic.jp/knowledge/accessibility/
    “ҰൠʹΞΫηγϏϦςΟͱ͸ɺΞΫηεͷ͠΍͢͞Λҙຯ͠·͢ɻస
    ͯ͡ɺ੡඼΍αʔϏεͷར༻͠΍͢͞ͱ͍͏ҙຯͰ΋࢖ΘΕ·͢ɻ”
    ΞΫηγϏϦςΟ
    10

    View Slide

  11. ΞΫηγϏϦςΟ
    • ো֐ऀ΍ߴྸऀ޲͚ͷରԠͱࢥΘΕ͕͕ͪͩɺશਓྨ͕৘ใʹ৮ΕͨΓػೳΛମݧ
    Ͱ͖Δ͜ͱΛ໨ࢦ͢


    • ಛʹը໘Λཁ͢Δ΢ΣϒαΠτ΍εϚʔτϑΥϯΞϓϦέʔγϣϯʹ͓͍ͯ͸ɺࢹ֮
    ো֐Λ࣋ͭਓ΍ࢹྗ͕௿Լͨ͠ਓʹෆศΛײͤͯ͡͞͠·͏͜ͱ͕ଟ͍ͨΊɺࢹ֮
    తͳαϙʔτΛߦ͏͜ͱ͕த৺ͱͳΔ


    • ྫ: ը໘ͷಡΈ্͛ػೳ΍ɺը໘΍ϑΥϯτͷ֦େػೳΛαϙʔτ


    • ͜ͷൃදͰ΋AppleϓϥοτϑΥʔϜͷΞΫηγϏϦςΟʹؔ͢ΔػೳͰ͋Δ
    VoiceOverΛத৺ʹ঺հ
    11

    View Slide

  12. ΢ΣϒΞΫηγϏϦςΟͷ4ͭͷݪଇ
    • ஌֮Մೳ


    • ৘ใٴͼϢʔβΠϯλϑΣʔείϯϙʔωϯτ͸ɺར༻ऀ͕஌֮Ͱ͖Δํ๏Ͱར༻ऀʹఏࣔՄೳͰͳ
    ͚Ε͹ͳΒͳ͍ɻ


    • ૢ࡞Մೳ


    • ϢʔβΠϯλϑΣʔείϯϙʔωϯτٴͼφϏήʔγϣϯ͸ૢ࡞ՄೳͰͳ͚Ε͹ͳΒͳ͍ɻ


    • ཧղՄೳ


    • ৘ใٴͼϢʔβΠϯλϑΣʔεͷૢ࡞͸ཧղՄೳͰͳ͚Ε͹ͳΒͳ͍ɻ


    • ݎ࿚ੑ


    • ίϯςϯπ͸ɺࢧԉٕज़ΛؚΉ༷ʑͳϢʔβΤʔδΣϯτ͕࣮֬ʹղऍͰ͖ΔΑ͏ʹे෼ʹݎ࿚Ͱͳ
    ͚Ε͹ͳΒͳ͍ɻ
    12
    https://waic.jp/docs/UNDERSTANDING-WCAG20/intro.html

    View Slide

  13. ϢʔβʔϏϦςΟͱͷؔ܎
    • ࢖͍΍͢͞ͱ͍͏ίϯςΩετͰΑ͘ར༻͞ΕΔ͕ϢʔβʔϏ
    ϦςΟ͸ΞΫηγϏϦςΟ͕อͨΕ্ͨͰҙ͍ࣝͨ͠


    • ͦ΋ͦ΋ΞΫηεͰ͖ͳ͚Ε͹ར༻͕Ͱ͖ͳ͍ͨΊ
    13

    View Slide

  14. ϢʔβʔϏϦςΟͱͷؔ܎
    • ࢖͍΍͢͞ͱ͍͏ίϯςΩετͰΑ͘ར༻͞ΕΔ͕ϢʔβʔϏ
    ϦςΟ͸ΞΫηγϏϦςΟ͕อͨΕ্ͨͰҙ͍ࣝͨ͠


    • ͦ΋ͦ΋ΞΫηεͰ͖ͳ͚Ε͹ར༻͕Ͱ͖ͳ͍ͨΊ
    14
    ϢʔβʔϏϦςΟ
    ΞΫηγϏϦςΟ

    View Slide

  15. ΠϯΫϧʔγϒσβΠϯ
    • ॅΜͰ͍Δ৔ॴ΍೥୅ɺੑผͳͲʹΑΔจԽͷҧ͍


    • ࿩ͨ͠Γฉ͍ͨΓɺॻ͍ͨΓಡΜͩΓ͢Δݴޠ
    15
    https://developer.apple.com/videos/play/wwdc2021/10275/
    https://developer.apple.com/videos/play/wwdc2021/10304/
    ͳͲ͜Ε·Ͱഉআ͞Ε͍ͯͨਓʑΛר͖ࠐΈͳ͕ΒแׅతʹσβΠϯ͢Δ
    ख๏
    ΞΫηγϏϦςΟ΍ϢʔβʔϏϦςΟ
    +

    View Slide

  16. ͳͥ ͰΞΫηγϏϦςΟ
    ͷ޲্ʹऔΓ૊Έ࢝Ί͔ͨ
    16

    View Slide

  17. औΓ૊Έ࢝Ί͖͔͚ͨͬ
    • ࣾ಺͔ΒΞΫηγϏϦςΟΛ޲্͍ͨ͠ͱ͍͏੠্͕͕Δ


    • ΋ͱ΋ͱΞΫηγϏϦςΟͷ޲্ʹڵຯ͕͋ͬͨ


    • ۀ຿ҕୗͱ͍͏ܗͰΞΫηγϏϦςΟʹؔ͢ΔΞυόΠεΛ͘ΕΔํ͕
    δϣΠϯ


    • noteͷ7प೥ه೦ΠϕϯτͰΞΫηγϏϦςΟʹ΋ྗΛೖΕΔࢫΛൃද


    • ໡໨ͷํ͔Βͷ໰͍߹Θ͕ͤ͋ΓϢʔβʔΠϯλϏϡʔΛ࣮ࢪ
    17

    View Slide

  18. औΓ૊Έ࢝Ί͖͔͚ͨͬ
    • ࣾ಺͔ΒΞΫηγϏϦςΟΛ޲্͍ͨ͠ͱ͍͏੠্͕͕Δ


    • ΋ͱ΋ͱΞΫηγϏϦςΟͷ޲্ʹڵຯ͕͋ͬͨ


    • ۀ຿ҕୗͱ͍͏ܗͰΞΫηγϏϦςΟʹؔ͢ΔΞυόΠεΛ͘ΕΔํ͕
    δϣΠϯ


    • noteͷ7प೥ه೦ΠϕϯτͰΞΫηγϏϦςΟʹ΋ྗΛೖΕΔࢫΛൃද


    • ໡໨ͷํ͔Βͷ໰͍߹Θ͕ͤ͋ΓϢʔβʔΠϯλϏϡʔΛ࣮ࢪ
    18

    View Slide

  19. ໡໨ͷํ΁ͷΠϯλϏϡʔΛ࣮ࢪ
    • ZoomͰ࣮ࢪ


    • ීஈͲͷΑ͏ʹnoteΛར༻͍ͯ͠Δ͔


    • noteͰࠔ͍ͬͯΔ͜ͱ͕ͳ͍͔
    19

    View Slide

  20. ໡໨ͷํ΁ͷΠϯλϏϡʔΛ࣮ࢪ
    • ZoomͰ࣮ࢪ


    • ීஈͲͷΑ͏ʹnoteΛར༻͍ͯ͠Δ͔


    • noteͰࠔ͍ͬͯΔ͜ͱ͕ͳ͍͔


    • iOSΞϓϦͰهࣄʹݟग़͠ը૾͕ઃఆͰ͖ͳ͍


    • هࣄΛެ։͢Δࡍʹϋογϡλάͷઃఆ͕͏·͍͔͘ͳ͍
    20

    View Slide

  21. هࣄʹݟग़͠ը૾͕ઃఆͰ͖ͳ͍༷ࢠ
    21

    View Slide

  22. هࣄΛެ։͢Δࡍʹϋογϡλάͷઃఆ͕͏·͍͔͘ͳ͍༷ࢠ
    22

    View Slide

  23. ͜ΕΒͷ༷ࢠΛݟͯࢥ͍·ͨ͠
    23

    View Slide

  24. όά΍Μ…
    24

    View Slide

  25. ଊ͑ํͷมԽ
    • ͜Ε·Ͱ͸ΞΫηγϏϦςΟΛ޲্ͤ͞Α͏ͱࢥͬͯ΋Ͳ͏ߦಈ͠
    ͍͍ͯͷ͔෼͔Βͳ͔ͬͨ


    • ࣮ࡍʹಈ༷͘ࢠΛݟΔ͜ͱͰɺͨͩͷෆ۩߹ͩͱଊ͑ΒΕΔΑ͏ʹ


    • ΞΫηγϏϦςΟ޲্Λܝ͛ͯ΋ͳ͔ͳ͔λεΫ͸ਐΈਏ͍


    • 1ͭͷόάमਖ਼ͱ͍͏λεΫʹ෼ղ͢Ε͹༏ઌ౓্͕͕ͬͯ͘Δ
    25

    View Slide

  26. VoiceOverͷ࢖͍ํ
    26

    View Slide

  27. VoiceOverͷ੾Γସ͑ํ๏
    27

    View Slide

  28. VoiceOverͷ؆୯ͳ࢖͍ํ
    28

    View Slide

  29. https://developer.apple.com/videos/play/wwdc2018/226/
    “VoiceOver: App Testing Beyond The Visuals”
    29

    View Slide

  30. ࣮ࡍʹൃੜͨ͠໰୊ͱͦͷղܾํ๏
    30

    View Slide

  31. ࣮ࡍʹൃੜͨ͠໰୊ͱͦͷղܾํ๏
    • tapGestureRecognizer͕ઃఆ͞Ε͍ͯΔUIView͕બ୒Ͱ
    ͖ͳ͍໰୊


    • ը૾ͷΈͷϘλϯͰҙਤ͠ͳ͍ಡΈ্͕͛͞Εͯ͠·͏໰୊


    • ϋʔϑϞʔμϧ͕ด͡ΒΕͳ͍໰୊
    31

    View Slide

  32. tapGestureRecognizer͕ઃఆ͞
    Ε͍ͯΔUIView͕બ୒Ͱ͖ͳ͍໰୊
    32

    View Slide

  33. ίʔυΠϝʔδ
    lazy var containerView: UIView = {


    let view = UIView(frame: view.bounds)


    view.isUserInteractionEnabled = true


    view.addGestureRecognizer(


    UITapGestureRecognizer(target: self, action: #selector(tap(sender:))))


    return view


    }()


    @objc private func tap(sender: UITapGestureRecognizer) {


    showTappedAlert()


    }
    33

    View Slide

  34. tapGestureRecognizer͕


    ઃఆ͞Ε͍ͯΔUIView͕બ୒Ͱ͖ͳ͍໰୊
    34

    View Slide

  35. मਖ਼಺༰
    view.isAccessibilityElement = true
    +
    35

    View Slide

  36. tapGestureRecognizer͕


    ઃఆ͞Ε͍ͯΔUIView͕બ୒Ͱ͖ͳ͍໰୊मਖ਼൛
    36

    View Slide

  37. ը૾ͷΈͷϘλϯͰҙਤ͠ͳ͍
    ಡΈ্͕͛͞Εͯ͠·͏໰୊
    37

    View Slide

  38. ίʔυΠϝʔδ
    lazy var button: UIButton = {


    let button = UIButton(type: .custom)


    let configuration = UIImage.SymbolConfiguration(


    font: UIFont.systemFont(ofSize: 280))


    let image = UIImage(systemName: "heart", withConfiguration: configuration)


    button.setImage(image, for: .normal)


    return button


    }()
    38

    View Slide

  39. ը૾ͷΈͷϘλϯ͕


    ҙਤ͠ͳ͍ಡΈ্͕͛͞Εͯ͠·͏໰୊
    39

    View Slide

  40. मਖ਼಺༰
    button.accessibilityLabel = "εΩ"
    +
    40

    View Slide

  41. ը૾ͷΈͷϘλϯ͕


    ҙਤ͠ͳ͍ಡΈ্͕͛͞Εͯ͠·͏໰୊मਖ਼൛
    41

    View Slide

  42. ϋʔϑϞʔμϧ͕ด͡ΒΕͳ͍໰୊
    42

    View Slide

  43. ϋʔϑϞʔμϧ͕ด͡ΒΕͳ͍໰୊
    43

    View Slide

  44. मਖ਼಺༰ 1
    lazy var closeButton: UIButton = {


    let button = UIButton(type: .custom)


    button.setTitle("ด͡Δ", for: .normal)


    button.addTarget(self, action: #selector(close(sender:)), for: .touchUpInside)


    return button


    }()


    @objc private func close(sender: Any) {


    dismiss(animated: true)


    }
    44

    View Slide

  45. मਖ਼಺༰ 2
    private var cancellable: AnyCancellable?


    private func subscribeVoiceOver() {


    cancellable?.cancel()


    cancellable = NotificationCenter.default.publisher(


    for: UIAccessibility.voiceOverStatusDidChangeNotification


    )


    .sink { [weak self] _ in


    self?.handleVoiceOverStatus()


    }


    }


    private func handleVoiceOverStatus() {


    closeButton.isHidden = !UIAccessibility.isVoiceOverRunning


    }
    45

    View Slide

  46. ϋʔϑϞʔμϧ͕


    ด͡ΒΕΔΑ͏ʹमਖ਼൛
    46

    View Slide

  47. ߋʹମݧΛ޲্ͤ͞Δ6ͭͷࢪࡦ
    47

    View Slide

  48. ߋʹମݧΛ޲্ͤ͞Δ6ͭͷࢪࡦ
    • ϑΥʔΧε͕౰͍ͨͬͯΔཁૉͰԿ͕Ͱ͖Δͷ͔Λ஌Β͍ͤͨ


    • Կ͔ಈ࡞Λͨ͠Β༻ҙͨ͠ςΩετΛಡΈ্͍͛ͨ


    • Կ͔ಈ࡞Λͨ͠ࡍʹϑΥʔΧε͞ΕΔ৔ॴΛࢦఆ͍ͨ͠


    • ೔෇ͷಡΈ্͛ΛࣗવʹରԠ͍ͨ͠


    • Ϧετը໘ͰεΠονͷON/OFFͷૢ࡞Λࣗવʹ͍ͨ͠


    • ݟग़͠δϟϯϓػೳ΁ͷରԠΛ͍ͨ͠
    48

    View Slide

  49. ϑΥʔΧε͕౰͍ͨͬͯΔཁૉͰ
    Կ͕Ͱ͖Δͷ͔Λ஌Β͍ͤͨ
    49

    View Slide

  50. 50
    Կ͕Ͱ͖Δͷ͔͕෼͔Βͳ͍༷ࢠ

    View Slide

  51. ରԠ಺༰
    51
    cell.accessibilityHint = "μϒϧλοϓͰ࡟আ"
    +

    View Slide

  52. 52
    Կ͕Ͱ͖Δͷ͔͕෼͔ΔΑ͏ʹͳ༷ͬͨࢠ

    View Slide

  53. Կ͔ಈ࡞Λͨ͠Β༻ҙͨ͠ςΩετ
    ΛಡΈ্͍͛ͨ
    53

    View Slide

  54. ίʔυΠϝʔδ
    54
    private func showErrorMessage(_ errorMessage: String) {


    errorLabel.text = errorMessage


    }

    View Slide

  55. 55
    Τϥʔ͕දࣔ͞Εͯ΋


    ؾ͚ͮͳ͍༷ࢠ

    View Slide

  56. ରԠ಺༰
    56
    private func showErrorMessage(_ errorMessage: String) {


    errorLabel.text = errorMessage


    UIAccessibility.post(notification: .announcement, argument: errorMessage)


    }
    +
    https://developer.apple.com/documentation/uikit/uiaccessibility/notification

    View Slide

  57. 57
    Τϥʔ͕දࣔ͞Ε͍ͯΔ͜ͱʹ


    ؾ͚ͮΔΑ͏ʹͳ༷ͬͨࢠ

    View Slide

  58. Կ͔ಈ࡞Λͨ͠ࡍʹϑΥʔΧε
    ͞ΕΔ৔ॴΛࢦఆ͍ͨ͠
    58

    View Slide

  59. Կ͔ಈ࡞Λͨ͠ࡍʹϑΥʔΧε͞ΕΔ৔ॴΛࢦఆ͍ͨ͠
    59

    View Slide

  60. मਖ਼಺༰
    @objc private func next(sender: Any) {


    UIAccessibility.post(notification: .layoutChanged, argument: messageLabel)


    }
    +
    60
    https://developer.apple.com/documentation/uikit/uiaccessibility/notification

    View Slide

  61. Կ͔ಈ࡞Λͨ͠ࡍʹϑΥʔΧε͞ΕΔ৔ॴΛࢦఆ͍ͨ͠ରԠ൛
    61

    View Slide

  62. ೔෇ͷಡΈ্͛ΛࣗવʹରԠ͍ͨ͠
    62

    View Slide

  63. ίʔυΠϝʔδ1
    lazy var dateLabel: UILabel = {


    let label = UILabel()


    label.textColor = .label


    label.font = UIFont.preferredFont(forTextStyle: .headline)


    label.textAlignment = .center


    label.numberOfLines = 0


    label.lineBreakMode = .byWordWrapping


    return label


    }()


    private func showNow() {


    dateLabel.text = dateFormatter.string(from: now)


    }
    63

    View Slide

  64. ίʔυΠϝʔδ2
    private lazy var dateFormatter: DateFormatter = {


    guard


    let dateFormat = DateFormatter.dateFormat(


    fromTemplate: "yyyy/MM/dd HH:mm", options: 0, locale: .current)


    else {


    fatalError("failed get date format from template")


    }


    var calendar = Calendar(identifier: .gregorian)


    let timeZone = TimeZone.current


    let locale = Locale.current


    calendar.locale = locale


    var dateFormatter = DateFormatter()


    dateFormatter.calendar = calendar


    dateFormatter.timeZone = timeZone


    dateFormatter.locale = locale


    dateFormatter.dateFormat = dateFormat


    return dateFormatter


    }()
    64

    View Slide

  65. 65
    ೔෇ͷಡΈ্͛ΛࣗવʹରԠ͢Δલ

    View Slide

  66. मਖ਼಺༰
    66
    private func showNow() {


    dateLabel.text = dateFormatter.string(from: now)


    dateLabel.accessibilityLabel = accessibilityDateFormatter.string(from: now)


    }


    private lazy var accessibilityDateFormatter: DateFormatter = {


    var calendar = Calendar(identifier: .gregorian)


    let timeZone = TimeZone.current


    let locale = Locale.current


    calendar.locale = locale


    var dateFormatter = DateFormatter()


    dateFormatter.calendar = calendar


    dateFormatter.timeZone = timeZone


    dateFormatter.locale = locale


    dateFormatter.dateStyle = .long


    dateFormatter.timeStyle = .medium


    return dateFormatter


    }()
    +
    +

    View Slide

  67. 67
    ೔෇ͷಡΈ্͛ΛࣗવʹରԠ൛

    View Slide

  68. Ϧετը໘ͰεΠονͷON/OFFͷૢ࡞
    Λࣗવʹ͍ͨ͠
    68

    View Slide

  69. 69
    Ϧετը໘ͰεΠονͷON/OFFͷૢ࡞վળલ

    View Slide

  70. मਖ਼಺༰
    70
    private func setUp() {


    isAccessibilityElement = true


    }


    override var accessibilityLabel: String? {


    get {


    titleLabel.text


    }


    set {}


    }


    override var accessibilityValue: String? {


    get {


    toggleSwitch.accessibilityValue


    }


    set {}


    }


    override var accessibilityTraits: UIAccessibilityTraits {


    get {


    toggleSwitch.accessibilityTraits


    }


    set {}


    }


    override func accessibilityActivate() -> Bool {


    toggleSwitch.isOn.toggle()


    return true


    }
    SwitchAccessibleViewCell.swift

    View Slide

  71. 71
    Ϧετը໘ͰεΠονͷON/OFFͷૢ࡞վળޙ

    View Slide

  72. ݟग़͠δϟϯϓػೳ΁ͷରԠΛ͍ͨ͠
    72

    View Slide

  73. ϩʔλʔػೳ
    • “VoiceOver ϩʔλʔΛ࢖ͬͯ VoiceOver ͷಈ࡞ΛมߋͰ͖·
    ͢ɻVoiceOver ͷԻྔ΍࿩͢଎͞Λมߋͨ͠Γɺը໘্Ͱ߲໨ؒ
    ΛҠಈͨ͠Γ͢Δ͜ͱ͕Ͱ͖ɺͦͷଞͷૢ࡞΋ՄೳͰ͢ɻ”

    https://support.apple.com/ja-jp/HT204783


    • 1ຊࢦͷ্ԼεϫΠϓͰར༻Մೳ


    • ը໘্Λ2ຊࢦͰճ͢Α͏ʹಈ͔͢͜ͱͰઃఆΛมߋ


    • ΧελϜػೳΛ࡞੒͢Δ͜ͱ΋Մೳ

    https://developer.apple.com/documentation/uikit/
    uiaccessibilitycustomrotor
    73

    View Slide

  74. ίʔυΠϝʔδ
    74
    private func makeHeadlineLabel(with title: String) -> UILabel {


    let label = UILabel()


    label.font = UIFont.preferredFont(forTextStyle: .headline)


    label.textColor = UIColor.label


    label.text = title


    label.numberOfLines = 0


    label.lineBreakMode = .byWordWrapping


    return label


    }

    View Slide

  75. 75
    ݟग़͠δϟϯϓػೳ΁ͷରԠલ

    View Slide

  76. मਖ਼಺༰
    76
    private func makeHeadlineLabel(with title: String) -> UILabel {


    let label = UILabel()


    label.font = UIFont.preferredFont(forTextStyle: .headline)


    label.textColor = UIColor.label


    label.text = title


    label.numberOfLines = 0


    label.lineBreakMode = .byWordWrapping


    label.accessibilityTraits = [.header]


    return label


    }
    +

    View Slide

  77. 77
    ݟग़͠δϟϯϓػೳ΁ͷରԠޙ

    View Slide

  78. 78
    static var none: UIAccessibilityTraits
    The accessibility element has no traits.


    static var button: UIAccessibilityTraits
    The accessibility element behaves like a button.


    static var link: UIAccessibilityTraits
    The accessibility element behaves like a link.


    static var image: UIAccessibilityTraits
    The accessibility element behaves like an image.


    static var searchField: UIAccessibilityTraits
    The accessibility element behaves like a search field.


    static var keyboardKey: UIAccessibilityTraits
    The accessibility element behaves like a keyboard key.


    static var staticText: UIAccessibilityTraits
    The accessibility element behaves like static text that can't change.


    static var header: UIAccessibilityTraits
    The accessibility element is a header that divides content into
    sections, such as the title of a navigation bar.


    static var tabBar: UIAccessibilityTraits
    The accessibility element behaves like a tab bar.


    static var summaryElement: UIAccessibilityTraits
    The accessibility element provides summary information when the app starts.


    static var selected: UIAccessibilityTraits
    The accessibility element is currently in a selected state.


    static var notEnabled: UIAccessibilityTraits
    The accessibility element isn't in an enabled state and doesn't respond to
    user interaction.


    static var adjustable: UIAccessibilityTraits
    The accessibility element allows continuous adjustment through a range of
    values.


    static var allowsDirectInteraction: UIAccessibilityTraits
    The accessibility element allows direct touch interaction for VoiceOver users.


    static var updatesFrequently: UIAccessibilityTraits
    The accessibility element frequently updates its label or value.


    static var causesPageTurn: UIAccessibilityTraits
    The accessibility element causes an automatic page turn when VoiceOver
    finishes reading the text within it.


    static var playsSound: UIAccessibilityTraits
    The accessibility element plays its own sound when the user activates it.


    static var startsMediaSession: UIAccessibilityTraits
    The accessibility element starts a media session when the user activates it.
    accessibilityTraits
    https://developer.apple.com/documentation/uikit/uiaccessibility/uiaccessibilitytraits

    View Slide

  79. ΞΫηγϏϦςΟͷઃఆΛ֬ೝ͢ΔTips
    79

    View Slide

  80. ΞΫηγϏϦςΟͷઃఆΛ֬ೝ͢ΔTips
    • ʮԻ੠ίϯτϩʔϧʯΛ༗ޮʹͯ͠
    ʮΦʔόʔϨΠʯͷઃఆΛʮ߲໨
    ໊ʯʹ͢Δ͜ͱͰઃఆࡁΈͷϥϕϧ
    ͕ՄࢹԽͰ͖Δ


    • VoiceOverΛ࣮ࡍʹ࢖Θͣͱ΋ϥϕ
    ϧͷ֬ೝ͕Ͱ͖ͯศར
    80

    View Slide

  81. Accessibility Inspector
    81
    • ΞΫηγϏϦςΟʹؔ͢ΔΑΓৄࡉ
    ͷ৘ใΛௐ΂Δʹ͸Xcodeʹ෇ଐͷ
    Accessibility InspectorΛར

    View Slide

  82. ΞΫηγϏϦςΟʹؔ͢Δςετ
    • SnapshotTesting

    https://github.com/pointfreeco/swift-snapshot-testing


    • AccessibilitySnapshot

    https://github.com/cashapp/AccessibilitySnapshot


    • A11yUITests

    https://github.com/rwapp/A11yUITests
    82

    View Slide

  83. ར༻ऀͷ੠
    • “ૉఢͳॻ͖खͱܨ͕Δ৔ॴͰ͋Γɺࢲࣗ਎͕ࣗ෼Λදݱ͢Δ৔ॴͰ͋ΔnoteͰ
    ͜Ε͔Β΋ॻ͍͍͖͍ͯͨɻͦͷҰาͱͯ͠ΞΫηγϏϦςΟͷվળ͸େ͖ͳྗ
    ʹͳͬͨɻ”

    https://note.com/azusa_1202/n/neeeb0112c395


    • “note͕ΞΫηγϏϦςΟʹऔΓ૊Ή͜ͱʹΑΓɺࢲͷΑ͏ͳεΫϦʔϯɾϦʔ
    μʔ࢖༻ऀ͚ͩͰͳ͘ɺ਎ମ΍ೝ஌ʹࠔ೉͞Λײ͡Δਓ΍ಡࣈো֐΍ॻࣈো֐ͳ
    Ͳɺ͍Ζ͍Ζͳ“ଟ༷ੑ”ʹԠ͑ΒΕΔαʔϏεʹ͍͍ۙͮͯ͘ͱࢥ͍·͢ɻ”

    https://note.com/kokoa_nattsu/n/nc08f81cda989
    83

    View Slide

  84. ࠓޙͷల๬
    • ͷ΢ΣϒɾΞϓϦͷΞΫηγϏϦςΟͷ޲্׆ಈ͸·ͩ·ͩ࢝
    ·ͬͨ͹͔ΓͰෆ׬શ


    • ΞΫηγϏϦςΟͷ޲্ʹΰʔϧ͸ͳ͍


    • ఆৗͷ։ൃɾ඼࣭؅ཧͷதʹ૊ΈࠐΜͰ։ൃΛਐΊͯߦ͖͍ͨ


    • ఆظతʹϢʔβʔΠϯλϏϡʔ΍ΞϯέʔτͳͲΛ࣮ࢪͯ͠ར༻ऀͷ੠Λ
    र্͍͍͛ͯ͘࢓૊Έͮ͘Γ
    84

    View Slide

  85. ·ͱΊ
    • ΞΫηγϏϦςΟΛ޲্͢Δͱҙؾࠐ·ͣʹόάΛमਖ਼͢Δͱ͍͏ҙࣝ


    • NSObject͕͍࣋ͬͯΔaccessibilityؔ࿈ϓϩύςΟ͔Β


    • ༻్ʹ߹ΘͤͯUIAccessibility΍Accessibility Frameworkͷ
    ػೳΛར༻ͯ͠ମݧΛ޲্Λ͍͚ͤͯ͞͹Αͦ͞͏


    • ΞΫηγϒϧͳΞϓϦ͕૿͑Δ͜ͱͰɺࠔ͍ͬͯΔਓ͕গ͠Ͱ΋ݮΕ͹
    85

    View Slide

  86. ৘ใऩू
    • https://developer.apple.com/accessibility/


    • https://a11yj.herokuapp.com

    #apple-app νϟϯωϧͰAppleϓϥοτϑΥʔϜʹؔ͢Δ৘ใަ׵


    • https://a11y-guidelines.orange.com/en/


    • https://accrefs.jp

    Webʹؔ͢Δ৘ใ͕΄ͱΜͲ͚ͩͲΞϓϦ΋গ͠
    86

    View Slide

  87. ͰͷऔΓ૊Έ
    • ΞΫηγϏϦςΟڧԽͷҰ؀ͰɺεΫϦʔϯϦʔμʔʹΑΔಡΈ্͛ͷΧ
    ΠθϯΛߦ͍·ͨ͠

    https://note.com/info/n/n4dbe29c380a1


    • VoiceOverɺDynamic TypeͳͲɺiOSΞϓϦͷΞΫηγϏϦςΟػೳ
    ͷڧԽΛߦ͍·ͨ͠

    https://note.com/info/n/nfcc92e285d96


    • ͳͲͳͲ
    87

    View Slide

  88. αϯϓϧίʔυ
    88
    https://github.com/fromkk/AccessibilitySampler

    View Slide

  89. 89

    View Slide