- PVSM.RU - https://www.pvsm.ru -
Доброго времени суток! Меня зовут Иван Смолин. Я iOS разработчик в Touch Instinct.
Сегодня я хочу рассказать, что из себя представляет технология VoiceOver в iOS. И как мы сделали футбольное приложение более удобным для людей, у которых есть нарушения зрения.
Это основанный на жестах способ чтения содержимого на экране мобильного устройства. Технология позволяет пользователям управлять своим мобильным устройством без необходимости видеть содержимое на экране. Она выступает в качестве посредника между интерфейсом приложения и пользователем, проговаривает вслух детали элементов интерфейса и действия в приложении.
Эта функция особенно полезна для людей с нарушениями зрения. VoiceOver упрощает использование мобильного устройства для людей с такого рода проблемами. Если эта функция активирована, пользователи могут ориентироваться в интерфейсе и понимать, какие действия нужно сделать и какими будут результаты этих действий. [1] [1]
Когда пользователь тапает по любому месту на экране, его мобильное устройство (iPhone, iPad, Watch) проговаривает вслух элемент, который находится в этом месте.
В подавляющем большинстве случаев ваше приложение уже будет хорошо работать с VoiceOver. Тут стоит отдать должное инженерам Apple — все стандартные компоненты полностью поддерживают технологию VoiceOver. Однако, иногда всё же нужно написать немного дополнительного кода, чтобы ваш интерфейс стал более удобным для людей с нарушениями зрения.
Бывают всего два типа компонентов, для которых нужно обязательно реализовывать поддержку VoiceOver самостоятельно:
Так как первый вид встречается довольно редко, мы рассмотрим подробно способы, которые позволят значительно улучшить ситуацию во втором случае.
В остальных случаях можно лишь повысить удобство использования при помощи дополнительных возможностей, которые предоставляет нам VoiceOver.
Если в приложении изначально закладывается поддержка вспомогательных технологий, таких как VoiceOver, то всё начинается с дизайна. Существует специальное руководство по обеспечению доступности веб-контента [2] и руководство, как применять этот стандарт для мобильных платформ [3]. Эти руководства стоит как минимум прочитать перед тем, как начинать рисовать дизайн.
После того, как макеты нарисованы, к ним необходимо приложить дополнительную информацию. Она не видна визуально, но имеет критическое значение для людей с нарушениями зрения. В случае VoiceOver такой информацией будет являться текстовое описание всех элементов экрана, с которыми пользователь может взаимодействовать: видеть или нажимать. Важно текстово описать их характеристики.
Переключать «запомнить меня» (4) на странице входа.
После получения локализованных строк можно начинать разработку. Для начала необходимо прочитать руководство по программированию специальных возможностей [4]. А затем уже углубиться в UIAccessibility API.
Этот протокол содержит в себе набор свойств, которые описывают пользовательские элементы интерфейса. Вспомогательные приложения используют эту информацию, чтобы помочь пользователям с ограниченными возможностями.
Этот протокол содержит очень много свойств, которые можно сгруппировать по критериям:
Отвечающие за описание элемента:
accessibilityTraits — комбинация (перечисление) характеристик, которыми обладает элемент. Эти характеристики помогают VoiceOver понять, как нужно взаимодействовать с элементом. Характеристик достаточно много [https://developer.apple.com/reference/objectivec/nsobject/1615202-accessibilitytraits [5]], перечислим только некоторые их них.
Если в вашем приложении есть проблемы с доступностью для людей с ограниченными возможностями, то чаще всего требуется правильно переопределить только первую группу свойств.
Теперь я приведу пример, как, используя вышеописанные свойства UIAccessibility, решить вполне конкретные проблемы в приложении.
В ходе тестирования был выявлен ряд недочётов, связанных с именованием кнопок в навбаре для VoiceOver. Мы решили порефакторить код создания кнопок, чтобы решить эти проблемы и сделать кнопки переиспользуемыми во всём приложении.
Для начала мы создали enum со списком всех кнопок и значениями, которые эти кнопки могут в себе хранить:
enum Button {
case calendar(date: Date)
case filter(isActive: Bool)
case alert(isActive: Bool)
case commentary
case share
case favorite(isSelected: Bool)
case addToCalendar
case edit
case close
}
Далее был создан extension, который создавал готовые инстансы UIBarButton
и UIButton
из значений enum’а:
extension Button {
private var icon: UIImage? {
switch self {
case .calendar(let date):
let icon = R.image.ic_calendar()
let dayOfMonth = // * get day of month * //
let iconWithDate = //* render icon with day of month number *//
return iconWithDate
case .filter(let isActive):
return isActive ? R.image.filter_active() : R.image.filter_inactive()
case .alert(let isActive):
return isActive ? R.image.notification_bell_title_bar_active() : R.image.notification_bell_title_bar_inactive()
case .commentary:
return R.image.icon_audio_commentary_off()
case .share:
return R.image.icon_share()
case .favorite(let isSelected):
return (isSelected ? R.image.starOn() : R.image.starOff())?.withRenderingMode(.alwaysTemplate)
case .addToCalendar:
return R.image.icon_calendar()
case .edit:
return R.image.edit()
case .close:
return R.image.close()
}
}
func buttonWith(target: Any, action: Selector, buttonSize: ButtonSize = .iconSize) -> UIButton {
let button = UIButton()
button.setImage(icon, for: .normal)
button.addTarget(target, action: action, for: .touchUpInside)
let size: CGSize
switch buttonSize {
case .custom(let customSize):
size = customSize
case .iconSize:
size = icon?.size ?? .zero
}
button.frame = CGRect(.zero, size)
return button
}
func barButtonWith(target: Any, action: Selector, buttonSize: ButtonSize = .iconSize) -> UIBarButtonItem {
let item = UIBarButtonItem(customView: buttonWith(target: target, action: action, buttonSize: buttonSize))
switch self {
case .calendar(let date):
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
item.accessibilityLabel = R.string.localizable.calendar()
item.accessibilityValue = dateFormatter.string(from: date)
item.accessibilityHint = R.string.localizable.select_date_to_filter_matches_hint()
case .filter(let isActive):
item.accessibilityLabel = R.string.localizable.filter()
item.accessibilityValue = isActive ? R.string.localizable.active() : R.string.localizable.inactive()
case .alert(let isActive):
item.accessibilityLabel = R.string.localizable.set_alerts()
item.accessibilityValue = isActive ? R.string.localizable.alerts_enabled() : R.string.localizable.alerts_disabled()
item.accessibilityHint = R.string.localizable.edit_match_alerts()
case .commentary:
item.accessibilityLabel = R.string.localizable.commentary_window_title()
case .share:
item.accessibilityLabel = R.string.localizable.share()
case .favorite(let isSelected):
item.accessibilityLabel = R.string.localizable.toggle_favorite()
item.accessibilityValue = isSelected ? R.string.localizable.in_favorites() : R.string.localizable.not_favorites()
case .addToCalendar:
item.accessibilityLabel = R.string.localizable.add_to_calendar()
case .edit:
item.accessibilityLabel = R.string.localizable.edit()
case .close:
item.accessibilityLabel = R.string.localizable.close()
}
return item
}
}
Создание кнопок в итоге выглядело вот так:
class SomeController {
private let navBarButtons: [Button] = [.commentary, .share, .addToCalendar]
private var navBarButtonItems: [UIBarButtonItem] {
return navBarButtons.flatMap {
switch $0 {
case .commentary:
return $0.barButtonWith(target: self,
action: #selector(self.onBtnCommentaryClicked),
buttonSize: .rightBarButtonSize)
case .share:
return $0.barButtonWith(target: self,
action: #selector(self.onBtnShareMatchClicked),
buttonSize: .rightBarButtonSize)
case .addToCalendar:
return $0.barButtonWith(target: self,
action: #selector(self.onBtnAddMatchToCalendarClicked),
buttonSize: .rightBarButtonSize)
default:
return nil
}
}
}
func updateBarButtons() {
navItem.setRightBarButtonItems(navBarButtonItems, animated: false)
}
}
После этих изменений в приложении появились не только правильные названия для VoiceOver, но и добавилась дополнительная информация, которая очень полезна для людей с нарушениями зрения. Например, при выборе кнопки календаря, прочитывается не только его название, но и выбранная дата.
Аналогично для кнопки уведомлений. Мы сообщаем пользователю, находится ли кнопка в выбранном состоянии (уведомления включены) или нет. Также мы сообщаем пользователю, что случится, если он тапнет по той или иной кнопке.
Такие небольшие улучшения значительно упрощают использование приложения.
Другим проблемным кейсом в приложении была таблица со статистикой команд. Для VoiceOver такая таблица представляет из себя просто набор аббревиатур и цифр, которые никак не связаны. Если мы попытаемся запустить приложение с включенным VoiceOver, то сразу станет понятно, что незрячим людям разобраться с этим набором бессмысленных слов просто невозможно.
Здесь мы использовали группировку элементов и специально подготовленные для VoiceOver строки. Например, заголовок таблицы теперь читается не как «PL W D L ± GD PTS», а в развёрнутом виде: «Table header: Played, Won, Drawn, Lost, Goal difference, Goal difference value, Points».
Каждая строка таблицы, как и заголовок, включает в себя полное описание полей: «Position: 4, Manchester United, Played: 36, Won: 21, Drawn: 9, Lost: 6, Goal difference: 72-38, Goal difference value: 34, Points: 72»
Если у вас есть матёрые тестировщики, которые умеют тестировать с закрытыми глазами — вам повезло. Однако часто ответственность за проверку функциональности ложится на плечи программиста.
Несмотря на то, что VoiceOver не поддерживается в симуляторе, тестировать приложение можно и на нём. В этом нам помогает утилита Accessibility Inspector, которая устанавливается вместе с Xcode.
В этой утилите можно:
По своему опыту могу сказать, что этой утилиты вполне достаточно для разработки, но недостаточно для полноценного тестирования. Так как она не проговаривает тексты и мы можем упустить очень важные проблемы, связанные со знаками препинания.
Лучше всего, когда у вас есть человек с нарушениями зрения, который может по-настоящему попробовать приложение с включенным VoiceOver. Нам повезло, у нас был неравнодушный пользователь, который прошёлся по всему приложению и составил детальное описание всех мест, где VoiceOver работает недостаточно хорошо. Мы смогли исправить все указанные недочёты. Он и дальше помогал нам улучшать доступность приложения, за что ему огромное спасибо.
VoiceOver является продвинутой технологией, которая позволяет вам делать по-настоящему доступные приложения для людей с нарушениями зрения.
Она встроена во все операционные системы Apple и работает фактически «из коробки». Поэтому независимо от того, пользуетесь ли вы VoiceOver или разрабатываете приложение с его поддержкой, VoiceOver везде будет работать одинаково и предсказуемо.
Качественно сделанные приложения с поддержкой VoiceOver могут даже удостоиться премии iOS Design Awards, как это случилось с Workflow в 2015 году.
The Workflow app was selected for an Apple Design Award in 2015 because of its outstanding use of iOS accessibility features, in particular an outstanding implementation for VoiceOver with clearly labeled items, thoughtful hints, and drag/drop announcements, making the app usable and quickly accessible to those who are blind or low-vision. [2] [7]
Наверное, каждая команда хотела бы получить такой же отзыв и о своём приложении. Старайтесь сделать всё возможное для ваших пользователей, чтобы им было удобно пользоваться приложением вне зависимости от их возможностей.
Автор: petropavel13
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/ios/256208
Ссылки в тексте:
[1] [1]: https://medium.com/@rapidvalue/apple-voiceover-the-advanced-screen-reading-technology-85c43424ab21
[2] руководство по обеспечению доступности веб-контента: https://www.w3.org/TR/WCAG20/
[3] руководство, как применять этот стандарт для мобильных платформ: https://www.w3.org/TR/mobile-accessibility-mapping/
[4] руководство по программированию специальных возможностей: https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/iPhoneAccessibility/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008785
[5] https://developer.apple.com/reference/objectivec/nsobject/1615202-accessibilitytraits: https://developer.apple.com/reference/objectivec/nsobject/1615202-accessibilitytraits
[6] FotMob: https://itunes.apple.com/app/id488575683
[7] [2]: https://developer.apple.com/videos/play/wwdc2015/103/
[8] How to Make VoiceOver More Friendly in Your iOS App: https://medium.com/bpxl-craft/how-to-make-voiceover-more-friendly-in-your-ios-app-8fac34ab8c51
[9] Developing Accessible Apps: https://medium.com/wayfindr/developing-accessible-apps-4311163fb0b6
[10] iOS Accessibility: https://medium.com/bpxl-craft/ios-accessibility-6e2093386ddd
[11] iOS Accessibility — Best Practices for the VoiceOver User Experience: https://medium.com/capital-one-developers/ios-accessibility-best-practices-for-the-voiceover-user-experience-dc08112ef16
[12] Источник: https://habrahabr.ru/post/328894/
Нажмите здесь для печати.