Реалізація підтримки VoiceOver для iOS-додатків
VoiceOver — screen reader, вбудований в iOS. Користувач взаємодіє з додатком через свайпи та дотики, а система зачитує вміст екрану голосом. Якщо ваш додаток не підтримує VoiceOver, невидячий користувач не може ним користуватися взагалі — не «незручно», а саме «не може».
App Store review не перевіряє доступність автоматично, але додатки для державного сектору, медицини та освіти часто вимагають відповідності WCAG 2.1 / Section 508 за контрактом.
Що ламається без розробки
Кастомні UIView і SwiftUI View
Стандартні UIButton, UILabel, UITextField — VoiceOver розуміє з коробки. Кастомні UIView з контентом, намальованим на CALayer — ні. VoiceOver бачить весь кастомний view як один елемент без опису.
Для UIKit: isAccessibilityElement = true, accessibilityLabel, accessibilityHint, accessibilityTraits. accessibilityLabel — що це таке («Кнопка додати в корзину»). accessibilityHint — що станеться при активації («Додає товар в корзину, переходить до оформлення»). accessibilityTraits — тип елемента (.button, .link, .image, .header, .selected).
Для SwiftUI: модифікатори .accessibilityLabel(), .accessibilityHint(), .accessibilityAddTraits(). Якщо кілька вкладених View потрібно об'єднати в один accessible елемент — .accessibilityElement(children: .combine) або .accessibilityElement(children: .ignore) + явна label.
Зображення без alt-тексту
UIImageView з isAccessibilityElement = false (за замовчуванням) — VoiceOver пропускає. Декоративні зображення — правильно. Змістовні — ні, потрібна accessibilityLabel. Іконки в кнопках: якщо UIButton містить лише UIImageView без тексту — потрібна accessibilityLabel на кнопці, інакше VoiceOver зачитає ім'я файлу або мовчатиме.
Порядок фокуса
VoiceOver обходить елементи по accessibilityActivationPoint — звичайно центр frame. Для складних layout (overlay, absolute positioning у SwiftUI, кастомні контейнери) порядок може бути хаотичним. Виправляється через accessibilityElements на батьківському контейнері — масив в потрібному порядку:
override var accessibilityElements: [Any]? {
get { [titleLabel, priceLabel, addButton] }
set { }
}
У SwiftUI — .accessibilitySortPriority() для управління порядком.
Модальні екрани та кастомні оверлеї
UIAlertController — VoiceOver фокусується автоматично. Кастомний UIView-оверлей поверх контенту — ні. Потрібно UIAccessibility.post(notification: .screenChanged, argument: firstElement) щоб перевести фокус на перший елемент оверлея. При закритті — post(notification: .screenChanged, argument: triggerButton) щоб повернути фокус на кнопку, яка відкрила оверлей.
accessibilityViewIsModal = true на контейнері оверлея — приховує фоновий контент від VoiceOver. Без цього користувач свайпом може «провалитися» крізь оверлей на задний контент.
Як ми проводимо аудит та впровадження
Включаємо VoiceOver (Cmd+F5 у Simulator або потрійний клік Home/Side Button на пристрої) і проходимо всі ключові флоу: онбординг, головний екран, основні дії (оформити замовлення, відправити повідомлення, відтворити медіа).
Фіксуємо: елементи без label, неправильний порядок фокуса, недосяжні елементи, модальні оверлеї без управління фокусом.
Інструменти: Accessibility Inspector (Xcode) — перевіряє контрастність, знаходить елементи без label без запуску додатка. XCTest з XCUIAccessibilityAudit (iOS 17+) — автоматизований аудит в UI-тестах.
Правки розставляємо за пріоритетом: спочатку навігація та ключові CTA, потім списки та форми, потім медіа-контент.
Термін: 3-5 днів для додатка середнього масштабу. Вартість залежить від кількості екранів та частки кастомних компонентів.







