Привет, Хабр! Недавно я говорил про адаптацию приложений для незрячих и неподвижных людей. И не договорил!
Сегодня расскажу, как изменить поведение контролов с помощью accessibilityTraits
и сделать жизнь незрячих чуть удобней. Знать работу этих трейтов (traits) важно, чтобы не писать свои костыли.
В первой части мы начали разбираться с адаптацией приложений для незрячих с помощью VoiceOver: подписали контролы, сгруппировали их, исправили навигацию. В этой статье пойдём дальше и рассмотрим «особенности», которые можно дать контролам, чтобы улучшить их работу для незрячих людей и в целом повысить удобство использования приложения.
UITraitCollection
, которые вы можете применять к контролам. Важно знать о них заранее, чтобы не придумывать своих решений. Я поделил их на три типа: .staticText
— для надписей, которые не меняются. Текст просто прочитается. .header
— заголовок: Добавить в пиццу, заголовок..button
— кнопка. Основной способ подписывать активные контролы: Изменить состав, кнопка..image
— картинка. .link
— ссылка. Редкий гость в приложениях, частый на сайтах. .searchField
— поиск. .staticText
ставится автоматически для всех надписей, а вот .header
для заголовка нужно поставить вручную. При этом нужен и .header
и .staticText
. .image
и подписываем .accessibilityLabel = "Пицца Пепперони Фреш с перцем"
. .selected
— добавляет «выбрано» перед названием контрола. Подходит для всех свитчеров и чекбоксов. .notEnabled
— добавляет «недоступно». Эта настройка не видна в Interface Builder
и управляется только программно. accessibilityTraits
это OptionSet
, поэтому к нему можно применять методы вставки .formUnion
и удаления .formIntersection
:class ToppingCell: UICollectionViewCell {
override var isSelected: Bool {
didSet {
if isSelected {
accessibilityTraits.formUnion(.selected)
} else {
accessibilityTraits.formIntersection(.selected)
}
}
}
...
}
.summaryElement
— первое, что скажет приложение после запуска. Например, приложение погоды после запуска может сразу рассказать о температуре, а музыкальный плеер расскажет о включенной песне и исполнителе. В нашем случае можно говорить статус доставки, если заказа уже оформлен. .updatesFrequently
— штука для таймеров. Новое значение будет проговариваться раз в несколько секунд. .causesPageTurn
— скролит после прочтения. Вызовется accessibilityScroll(.next)
у того контрола, который сможет это обработать. Смотрит по .firstResponder
. .startsMediaSession
— обычно VoiceOver повторяет название нажатой кнопки, чтобы подтвердить действие. Это мешает, если контрол проигрывает звук. Включите этот трейт, чтобы VoiceOver не повторял название контрола. .playsSound
— стоит включить, если вы проигрываете собственный звук при фокусировании на контроле (если я всё правильно понял, сам ни разу не использовал)..allowsDirectInteraction
— для рисования и обработки жестов. Контрол сразу обрабатывает касание, будто VoiceOver выключен. .keyboardKey
— контрол начинает реагировать, как кнопка на клавиатуре. У VoiceOver есть несколько режимов ввода текста для таких случаев: standart typing
— как простая кнопка в VoiceOver: сначала наведите фокус на букву, а затем нажмите дважды в любом месте, чтобы написать её. Набирать можно быстрее двумя руками: одним пальцем водить по клавиатуре (буквы будут озвучиваться) и касаться другим пальцем, чтобы подтвердить выбор клавиши. touch typing
— однорукий ускоренный набор: водите пальцем по клавиатуре, чтобы озвучить кнопки. Отпустите палец, чтобы написать букву. direct touch typing
— как обычный набор, будто VoiceOver выключен. .adjustable
— элемент, который можно регулировать: так работают UIStepper
и UISlider
. Свайпните такой контрол вверх или вниз, чтобы изменить значение (не забывайте, что свайп влево/вправо переключит фокус на соседний элемент). Если у контрола есть UIPanGestureRecognizer, то можно тапнуть дважды и задержать второй тап, так жест сработает и можно управлять им напрямую, будто VoiceOver выключен..adjustable
:.adjustable
..accessibilityValue
.override public func awakeFromNib() {
super.awakeFromNib()
isAccessibilityElement = true // 1
accessibilityTraits = .adjustable // 2
}
extension SegmentedControl {
override public func accessibilityIncrement() { // 3
controller.selectNext(increment: +1)
}
override public func accessibilityDecrement() { // 3
controller.selectNext(increment: -1)
}
public override var accessibilityValue: String? { // 4
get {
return selectedSegment?.accessibilityValue
} set { }
}
}
accessibilityIncrement()
, вы увеличите внутренний счётчик, и VoiceOver прочитает новое значение из accessibilityValue.
view
и превратить в один контрол: «Количество, 1, 575 рублей. Элемент регулировки». После вертикального свайпа изменится количество, а затем произнесётся новое значение вместе с ценой.UICollectionView
. Оказалось, что .adjustable
удобно применять и для горизонтальных UICollectionView
. Например, выбрать акцию в меню или машину в такси. Чтобы не пропустить следующую статью, подписывайтесь на мой канал Dodo Pizza Mobile.
А ещё у нас сейчас открыта одна вакансия в мобильном направлении. Так что я просто оставлю это здесь: Senior iOS Developer (Нижний Новгород).
К сожалению, не доступен сервер mySQL