company_banner

Voice Control и VoiceOver: как адаптировать приложение для незрячих или неподвижных

    Представь, что ты незрячий. Вот так ты услышишь эту картинку: «Буква D в чёрных очках и с белой палочкой и буква O в инвалидной коляске смотрят на большой телефон. На экране телефона скриншот приложения Додо Пиццы, который проговаривает названия ячейки меню из пицц для VoiceOver. Картинка стилизована под старые компьютеры и выполнена в зелёных цветах. Нажать кнопку «Читать дальше».


    Буква D в чёрных очках и с белой палочкой и буква O в инвалидной коляске смотрят на большой телефон. На экране телефона скриншот приложения Додо Пиццы, который проговаривает названия ячейки меню из пицц для Voice Over.  Картинка стилизована под старые компьютеры и выполнена в зелёных цветах.


    Адаптация iOS-приложения — большая тема, в одну статью всё не влезло, поэтому выпускаю их серией.

    1. Voice Control и VoiceOver: как адаптировать приложение для незрячих или неподвижных.
    2. VoiceOver на iOS: каждый контрол ведёт себя по-разному.
    3. VoiceOver на iOS: решение типовых проблем.
    4. Разница между реализацией VoiceOver, Voice Control и UI тестов. (In progress)

    Телефон давно стал продолжением меня, и я слабо представляю свою жизнь без пары десятков приложений, которыми пользуюсь каждый день. Но как быть тем, кто не может взять телефон в руку или посмотреть на экран? Фичи iOS открывают людям с ограничениями в движении, зрении и слухе эти возможности в обычной жизни. С их помощью можно увеличить размер текста и контраст, сделать моно-аудио, убрать анимации. Можно работать с интерфейсом без экрана — на слух (для незрячих) или вообще управлять только голосом (если человек ограничен в движении).


    Адаптировать можно любое приложение и даже некоторые игры. Сегодня я расскажу как iOS-разработчикам сделать первые шаги в этом направлении.


    Voice Control: управляй голосом


    Начиная с iOS 13 телефон можно контролировать голосом. Voice Control упрощает жизнь и даёт новый уровень свободы людям с ограничениями в движении. Посмотрите видео, в нём Apple показывает, как именно это работает:



    Ещё более детально об управлении телефоном можно узнать вот в этих видео:


    1. Навигация голосом в вашем iPhone (How to navigate with Voice Control on your iPhone).
    2. Как использовать диктовку и редактировать текст с помощью голосового управления на вашем iPhone (How to use dictation and edit text with Voice Control on your iPhone).

    Включив эту функцию, вы сможете отдавать команды телефону. Увы, пока работает только с английским языком. Например, говоришь «tap purchase», — и кнопка купить нажимается. Для управления кнопками с иконками (без названий в виде слов) можно скомандовать «show numbers», и у всех кнопок появятся цифровые подписи. Теперь можно сказать «tap five» и пятая кнопка нажмётся.


    Для работы со сложными элементами (карты, графики), можно попросить телефон показать сетку, тогда место на карте можно будет выбирать по номеру ячейки.


    Доступных жестов очень много. Полное описание всех вы можете посмотреть в настройках телефона: Settings → Accessibility → Voice Control → Customize Commands.


    Три примера работы Voice Control: когда показывает надписи, цифры и сетку


    VoiceOver: управляй жестами


    Чтобы вашим приложением могли пользоваться незрячие люди, его нужно адаптировать с помощью VoiceOver. Несколько отличий от обычного использования:


    1. Вместо взгляда по экрану скользит палец. Когда палец оказывается на кнопке, телефон говорит её название и наводит на неё фокус в виде чёрной рамки. После этого можно нажать дважды в любом месте, кнопка нажмётся. Ещё можно переключаться между соседними элементами свайпом влево или вправо.
    2. Доступны дополнительные жесты: для навигации, для важных действий, для сложных элементов управления, например, слайдеров.
    3. Экран можно выключить, ведь он не нужен. Для этого тапните тремя пальцами трижды.

    Полный список доступных жестов.


    Как сделать ваше приложение доступным


    Voice Control и VoiceOver работают на одной технологии, поэтому адаптировав одно, мы получаем поддержку второго.


    Для начала нужно побыть пользователем: включить, попробовать поюзать самостоятельно и настроить шорткат (быстрое включение), чтобы легко было проверять новые фичи.


    Где включить: включать/отключать можно через Siri или через настройки (Settings → Accessibility → VoiceOver).


    Как настроить шорткат: для быстрого доступа включите шорткат на тройное нажатие кнопки «домой» (или «выключить» для X моделей): Settings → Accessibility → Accessibility Shortcut → Поставить галочку рядом с VoiceOver.


    Программируем (теория)


    Основа доступности — протокол UIAccessibilityElement. Для улучшения работы VoiceOver нужно:


    • Подписать кнопки.
    • Добавить значения.
    • Оставить подсказки.
    • Сгруппировать контролы.
    • Поправить неправильные надписи.
    • Указать тип контрола: кнопка, надпись, ссылка и т.д.

    Что-то можно настроить в Interface builder, но часть настроек доступна только в коде.


    Пример Interface Builder и настройками для Voice Over


    Названия кнопок — .accessibilityLabel


    Каждой кнопке надо дать короткое звучное название. VoiceOver подстрахует, если вы забыли — попытается прочитать текст или название иконки на кнопке, но часто получается так себе.


    Что нужно подписывать:


    • Кнопки с иконкой, но без текста;
    • UISlider;
    • UIStepper;
    • Картинки. Если есть возможность, то лучше подписать, что изображено на картинке. Instagram это умеет.

    Значения — .accessibilityValue


    Дополнительно к названию можно написать значение. Например, у слайдера будет название «яркость», а значение — «50%». У кнопки «Добавить в корзину» стоит указать количество или итоговую цену, чтобы подытожить действие всего экрана и не купить лишнего.


    Подсказки — .accessibilityHint


    Если вы хотите дополнительно пояснить действие, то можно записать подсказку в .accessibilityHint. Но сильно полагайтесь на подсказки не стоит: постоянные пояснения надоедают, поэтому некоторые пользователи отключают их через настройки телефона.


    Обобщение контролов


    По умолчанию проговаривается каждый контрол по отдельности. Это неудобно: зоны нажатий уменьшаются, можно что-то не заметить и т.д. Нужно обобщать. Например, в меню ячейка состоит из картинки, названия, описания и кнопки с ценой. Такая детальность не нужна: маленькую картинку можно скрыть, название и цену прописать в заголовок ячейки, а состав в её значение. Ячейка станет одним целым, а меню превратится в нормальный набор продуктов.


    Программируем (демо и практика)


    Этих знаний достаточно, чтобы начать улучшать собственную программу. Разберём на примере меню с пиццами.


    Неадаптированная версия для незрячего выглядит так:


    На чёрном экране написаны подписи элементов Voice Over на примере приложения Додо Пиццы


    Несколько очевидных проблем, которые предстоит решить:


    • Непонятное значение 24 в правом верхнем углу.
    • Пустое место слева и сверху.
    • Слишком много элементов.
    • Неправильное произношение цены («от двести сорок пять знак рубля» вместо «от двести сорок пять рублей»).

    Добавляем значения


    24 в правом верхнем углу — это количество додо-рублей.
    Так и надо подписать:


    accessibilityLabel = "Додо-рубли"
    accessibilityValue = amountOfDodoRubles

    Этот код можно разместить в любом месте, где у вас есть актуальное значение для value.


    Для кнопки города можно сделать нечто похожее: лейбл — ваш город, значение — Москва. Но можно и не делать, вроде и так понятно. Не переусердствовать — тоже важная задача.


    Убираем пустое место сверху


    Акции вверху — это горизонтальный UICollectionView. Внутри ячейки есть лейбл, именно его находит VoiceOver.


    Как поправить:


    1. Сделать всю ячейку доступным контролом. По умолчанию все view выступают только контейнерами для других элементов, VoiceOver их игнорирует. Чтобы пометить view, как конечный элемент, нужно поставить ячейке isAccessibilityElement = true. Это можно сделать в методе awakeFromNib(). После этого выделяться начнёт вся ячейка, пустое место больше не мешает.
    2. Дать ячейке название. На лейбле больше нельзя сфокусироваться, поэтому нужно вручную указать текст. accessibilityLabel = specialOffer.title

    Настроить можно в методе cellForItemAt:


    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let specialOffer = specialOffers[indexPath.row]
    
        let cell = collectionView.deque…
        cell.accessibilityLabel = specialOffer.title
    
        return cell
    }

    Упрощаем табличную ячейку


    У ячейки с продуктом две проблемы: много элементов и неправильное описание цены.


    Объединяем контролы

    Сейчас у ячейки несколько полей: название, описание, цена и картинка, 4 контрола на ячейку. Если в меню 10 продуктов, то это уже 40 маленьких контролов. Надо обобщить, чтобы было 10 продуктов, так получается ближе к смыслу.


    Ячейка меню, в которой элементы не сгруппированы


    Можно упростить:


    1. Сделать всю ячейку доступным контролом. Это мы уже умеем: ставим ячейке isAccessibilityElement = true
    2. В accessibilityLabel записать самое важное: название и цену. Разделим запятой, VoiceOver учитывает пунктуацию.
    3. В accessibilityValue указать дополнительную информацию, в нашем случае это состав.
    4. Указать, что ячейку можно нажать, т.е. по сути это кнопка. accessibilityTraits = .button

    Ячейка меню, которая работает как одно целое для Voice Over


    Метод внутри ячейки, подставляет нужные значения:


    func refreshAccessibility(title: String?,
                              price: String?,
                              ingredients: String?,
                              isProductAvailable: Bool) {
            isAccessibilityElement = true // 1
    
            let price = isProductAvailable ? price : "Нет в наличии"
            accessibilityLabel = [title, price].compactMap { $0 }
                                               .joined(separator: ", ") // 2
    
            accessibilityValue = ingredients // 3
            accessibilityTraits = .button // 4
        }

    Группировать можно не только ячейки, но и все связанные смыслом контролы. Например, переключатель количества и цену стоит обрабатывать вместе: изменили количество — сказали новую цену. Тогда вместо четырёх глупых контролов появится один нормальный.


    Пример объединения четырёх контролов: кнопки минус, надписи с количеством, кнопки плюс и цены за все продукты


    Склоняем «рубли»


    Для правильного написания «рублей» мы генерируем правильную строку и ставим её в accessibilityLabel для кнопки.


    buyButton.accessibilityLabel = String(format: NSLocalizedString("от %d рублей", comment: "Price button. Ex.: от 150 рублей"), price)

    Просклонять нужно в файле Localizable.stringsDict:


    Пример локализации для множественных чисел



    Для навигации есть два вспомогательных жеста: скрабл и меджик тап.


    Скрабл возвращает на предыдущий экран. Чтобы его выполнить, проведите по экрану двумя пальцами, будто пишите букву Z. Ещё скраблом можно заканчивать ввод текста.


    Меджик тап вызывает главную функцию текущего экрана. Нужно тапнуть дважды двумя пальцами. Можно включить песню в плеере или ответить на звонок.


    У меджик тапа есть UX-проблема — неочевидно, что он делает. Для себя мы решили так: если скрабл переходит на экран назад, то пусть меджик тап переводит на следующий экран по сценарию. На карточке пиццы это добавит её в корзину, если вы были в корзине, то перейдёте на экран доставки, а с доставки переключитесь на оплату.


    Но если действие неочевидно, то можно рассказать о меджик тапе в подсказке у кнопки. Но помните: подсказки могут не проговариваться, зависит от настроек.


    Адаптируем навигацию


    Если нажать на акцию или кнопку додо-рублей, откроется модальный экран. Если бы мы использовали UINavigationController, то ничего делать было бы не нужно. Но для модальных экранов нужно описать, как они реагируют на дополнительные жесты.


    Пример всплывающего окна


    Добавляем скрабл

    После того, как пользователь нарисует Z, вызовется метод accessibilityPerformEscape у firstResponder. Обычно, это текущий UIViewController.


    Вам достаточно реализовать этот метод, закрыть в нём экран и вернуть true, показав, что жест обработан и можно не проходить responder chain дальше:


    override func accessibilityPerformEscape() -> Bool {
            dismiss(animated: true)
            return true
        }

    Похожим образом можно реагировать на меджик тап. Например, применить акцию из карточки:


    override func accessibilityPerformMagicTap() -> Bool {
        applySpecialOffer()
            return true
        }

    Как находить проблемы


    Проблемы адаптации находить несложно, стоит только включить VoiceOver, как на вас посыпятся десятки. Но спустя время находить новые проблемы станет сложнее, при этом легко пропустить что-то важное, ведь проблемы приходится находить на слух. Есть пара способов упростить жизнь разработчику.


    1. Включить субтитры. В iOS 13 появилась настройка, которая включает «субтитры»: Settings → Accessibility → VoiceOver → Caption Panel.
    2. Смотреть подписи через Voice Control. При тестировании VoiceOver можно включить Voice Control, тогда все надписи будут видны сразу. Если где-то цифра, то вы забыли прописать .accessibilityLabel.
    3. Accessibility Inspector. Accessibility Inspector даёт возможность посмотреть все accessibility свойства в симуляторе. Ещё он может сделать аудит текущего экрана, так вы узнаете о возможных проблемах: малые области нажатия, неконтрастные элементы, неподписанные кнопки. Если нужно, то может прочитать голосом все элементы.

    Пока на этом всё


    Мы адаптировали один экран. Программировать нужно совсем немного, поддерживать доступность на базовом уровне легко.


    Но за кадром осталось многое: разные accessibilityTraits, набор текста, навигация в приложении, custom actions, порядок фокусировки, accessibility notifications, ротор и клавиатуру Брайля. Об этом в следующий раз.


    Если уже сейчас хотите узнать больше, то можно почитать:



    Чтобы не пропустить следующую статью, подписывайтесь на канал Dodo Pizza Mobile.

    Dodo Pizza Engineering
    О том как IT доставляет пиццу

    Комментарии 18

      –7
      IMHO, лучше написать отдельное приложение, заточенное под Accessibility.
        +4

        Это частое заблуждение. Почему вы так считаете? Почему со стороны разработки или бизнеса отдельное приложение эффективней?


        Из текста статьи: нам понадобилось добавить несколько подписей для одного экрана. Суммарно это пара часов.


        Если делать отдельное приложение, то вам нужно будет снова писать работу с базой, сетью, интерфейсом (как вы с ним будете работать? приложение всегда будет без UI?). Тестировать это, релизить. Нужны отдельные программисты, проектировщики, аналитики, тестировщики. Выходит намного больше работы. Никакой бизнес отдельное приложение не одобрит.


        При этом, приложения для незрячих вполне себе имеют и обычный интерфейс.

          0
          Если коротко, то причины те же, почему большинство компаний предпочитают нативную разработку под iOS и Android, вместо использования React Native, Flutter, etc. И да, это разные команды и т.д. и т.п.
            +3

            Ок, но не вижу общего в сравнении с нативной разработкой. Обычные интерфейсы прекрасно работают после небольшой адаптации.


            Я общался с незрячими ребятами: им не нужны специальные версии, нативный способ работает хорошо. Это не сложно и хорошо встраивается в обычное создание фич.

              –2
              Общее в том, что это все-таки разные интерфейсы, как ни крути. Понятно, что для разработчика это всего лишь фича (а для компании — пиар, чего уж там). Было бы интересно услышать мнение product менеджера. Уверен, здесь поле непаханое, чтобы развернуться и сделать спец. версию. Но бизнесу это не нужно, это да, слишком мала доля ЦА. А нужно ли это ЦА — для этого нужно вначале попробовать.
                0

                Не понимаю на какой опыт вы опираетесь, когда говорите, что нужно отдельное приложение.

                  0
                  Подскажу, конечно:
                  yandex.ru/search/?text=приложение%20для%20незрячих&lr=1091

                  Например, первые же ссылки, там и про заказ еды есть:
                  www.specialview.org/article/post501
                  www.specialview.org/article/advice80
                    +2

                    Вы привели примеры программ, половина которых решает исключительные проблемы незрячих: распознавание банкнот, звонки для распознавания предметов, ориентация на местности. Эти программы работают на той же технологии, что описан в статье.


                    Есть и игры, которые рассчитаны только на звук, например Blind Knight. Но играть в него могут все.


                    Нет причин, почему незрячий или неподвижный не может заказать пиццу, написать сообщение в соц сети, вызвать такси, перевести денег другу или опубликовать фотку в той же программе, в которой это делают все.

                      –3
                      Давайте рассмотрим док-во от противного. Представим, что большинство людей незрячие и все приложения сделаны под Voice Over с доп. функциями для небольшого числа зрячих. Могут ли зрячие ими пользоваться? Безусловно. Удобно ли им, по сравнению с визуальным интерфейсом? Вряд ли (не говоря уже о скорости восприятия информации).
                        +1
                        Вот что за бред.Вам же говорят, не нужно ничего дополнительного. Создается обычный GUI интерфейс для зрячего человека. Просто писать его надо по правилам и тогда он совершенно доступен и незрячим. Например когда создаете кнопочку, не забываем ставить ей текстовую метку названия. Даже если на кнопке хотите показать только картинку, без надписи, у кнопок есть специальный атрибут для текстовой метки, который визуально не виден, а доступен программам экранного доступа. Это также само как атрибут «alt» в теге
                        <img src="путь_к_картинке" alt="текстовое описание">
                        

                        , про который многие забывают почему-то. И все, представляете, от вас требуется к кнопке добавить всего лишь 1 атрибут, дело на 10 секунд, а незрячие уже увидят в вашей программе кнопку с нормальным названием, вместо: «Без ярлыка».
                    +1
                    Не нужны никакие специальные версии!!! Нативный GUI хорошо озвучивается, и надо просто писать хороший код, по всем правилам, с метками и прочей текстовой информацией. Никаких специальных версий не нужно. Как раз большинство тех флотеров и электронов как раз не озвучиваются, за некоторыми исключениями.facebook не имеет никаких специальных версий и им прекрасно пользуются незрячие, та множество программ используются совершенно обычные, просто правильно написанные.
                      +2
                      Кстати по поводу электрона у меня пока скорее положительные впечатления. :) skype и slack доступны и на андроид, и на ПК, в отличие от нативных viber и telegram. Их десктопными версиями пользоваться абсолютно невозможно. Так что, например, тот же QT у меня вызывает куда больше негативных ощущений.
                        0
                        Ну я говорил про мобильные нативные. А насчет электрон, как я и написал, за некоторыми исключениями. Как пример skype или vscode, то есть продукты microsoft как раз и являются этими приятными исключениями. Возможно и слэк, не знаю, его не использовал. Большинство других не доступны. Если рассматривать десктопные приложения, то телеграмм написан как раз на том QT, которыый как раз недоступный по нормальному, только через ужасные костыли. Насчет вайбер не знаю, может тоже что-то из подобных библиотек.Ведь нативность на десктопе не так влияет на доступность, как библиотеки для создания GUI. Поясню, что я имею ввиду. Не важно на каком языке писать, C++, python, или какой другой язык, доступность зависит от библиотеки для создания GUI интерфейса. Например, тот же QT не доступен по нормальному, а вот WX Widgets прекрасно озвучивается программами экранного доступа. Да что там, самое нативное, элементы управления, созданные WIN32API вполне доступны и озвучиваются в своей мере.
                          +1

                          Микрософт много внимание уделяет доступности. Недавно они опенсурсили компоненты для иос разработки, там каждый адаптирован для VoiceOver.

                            0
                            Да, у них почти все продукты, если не все, сделаны качественно с доступностью. За что им конечно отдельное спасибо.
                    +2
                    Вот, если честно, ни разу не видел, чтобы компании делали специальную адаптированную версию приложения чисто для незрячих. И, надеюсь, не увижу, т.к. она в любом случае не будет иметь всего функционала и рано или поздно забросится. А вот хорошо адаптированных приложений достаточно. На андроиде к ним все гугловские можно отнести, KateMobile, сбербанк, WhatsApp, telegram, etc. Еще больше тех, которыми можно пользоваться, но какие-то моменты делать неудобно. На звонки в viber отвечать, например, будильник на часах от хуавэй ставить. Вот над этим, как справедливо выше указали, и надо работать.
            +3
            Неадаптированная версия для незрячего выглядит так:

            Насколько я понимаю, вы сами нарисовали эту версию для незрячего? Это выглядит очень интересно. Помогает легче намного быстрее понять что надо поправить. Спасибо за идею.
              +2

              Да, сам нарисовал. Для каждого экрана удобно рисовать схему всех подписей. В iOS 13 стало легче, потому что можно включить Voice Control и он покажет сам.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое