#ios #swift #accessibility #voiceover #becomefirstresponder
#iOS #быстрый #Специальные возможности #голос за кадром #станьте первым ответчиком #swift
Вопрос:
ОБЗОР У меня возникли проблемы с получением правильного порядка фокусировки (доступность в iOS). Похоже, что becomeFirstResponder() перезаписывает мой порядок фокусировки, который я указал в массиве, и заставляет функцию голосового доступа сначала считывать неправильную метку доступности.
ПОДРОБНОСТИ: у меня есть контроллер представления с containerView. Внутри у меня есть UIView моего изображения индикатора выполнения и поля ввода текста (заполнителя). Оба элемента имеют атрибуты isAccessibilityElement = true, и они были добавлены в мой массив порядка фокусировки. Однако при запуске экрана порядок фокусировки переходит в поле ввода вместо индикатора выполнения UIView.
После расширенного тестирования я заметил, что эта проблема больше не воспроизводится, если я удалю нижеприведенную строку кода.
otpNumberTextField.becomeFirstResponder()
Но это не решение. Мне нужен курсор в текстовом поле, но функция озвучивания, чтобы сначала прочитать метку доступности индикатора выполнения. Как это исправить?
КОНКРЕТНЫЙ СЦЕНАРИЙ Я заметил, что эта проблема возникает только тогда, когда у меня есть VC с последним активным фокусом на текстовом поле, а затем переход к следующему VC (с текстовым полем и индикатором выполнения).
Ошибка не воспроизводится, когда у меня есть VC с последним активным фокусом на кнопке, а затем переход к следующему VC (с текстовым полем и индикатором выполнения).
ФРАГМЕНТ КОДА
import UIKit
class MyViewController: UIViewController, UITextFieldDelegate {
var otpNumberTextField = UITextField()
var progressMainDot = UIImageView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
setupView()
setupBinding()
}
override func viewWillAppear(_ animated: Bool) {
setupView()
textFieldDidChange(otpNumberTextField)
}
func setupView(){
let containerView = UIView()
containerView.backgroundColor = UIColor.init(named: ColourUtility.BackgroundColour)
view.addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
containerView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
//Progress Bar
let progressBarView = UIView()
containerView.addSubview(progressBarView)
progressBarView.isAccessibilityElement = true
progressBarView.accessibilityLabel = "my accessibility label"
progressBarView.translatesAutoresizingMaskIntoConstraints = false
progressMainDot.image = UIImage(named:ImageUtility.progressMain)
progressMainDot.contentMode = .scaleAspectFit
progressBarView.addSubview(progressMainDot)
//Text Field
otpNumberTextField.borderStyle = UITextField.BorderStyle.none
otpNumberTextField.font = UIFontMetrics.default.scaledFont(for: FontUtility.inputLargeTextFieldStyle)
otpNumberTextField.adjustsFontForContentSizeCategory = true
otpNumberTextField.isAccessibilityElement = true
otpNumberTextField.accessibilityLabel = AccessibilityUtility.enterVerificationCode
otpNumberTextField.placeholder = StringUtility.otpPlaceholder
otpNumberTextField.textColor = UIColor.init(named: ColourUtility.TextfieldColour)
otpNumberTextField.textAlignment = .center
otpNumberTextField.keyboardType = .numberPad
otpNumberTextField.addTarget(self, action: #selector(self.textFieldDidChange(_:)), for: .editingChanged)
containerView.addSubview(otpNumberTextField)
otpNumberTextField.becomeFirstResponder()
//Accessibility - focus order
view.accessibilityElements = [progressBarView, otpNumberTextField]
}
//... more code goes here ...
}
Ответ №1:
Если вы уже установили accessibilityElements
, то voice over должен соблюдать этот порядок, но вызов becomeFirstResponder()
изменяет фокус на это текстовое поле.
Вы можете попробовать приведенный ниже код, который уведомляет голос за кадром о переносе фокуса на новый элемент из-за изменений макета.
UIAccessibility.post(notification: .layoutChanged, argument: progressBarView)
Итак, теперь ваш модифицированный метод должен быть таким, как показано ниже:
func setupView(){
.....
otpNumberTextField.becomeFirstResponder()
//Accessibility - focus order
view.accessibilityElements = [progressBarView, otpNumberTextField]
UIAccessibility.post(notification: .layoutChanged, argument: progressBarView)
.....
}
Комментарии:
1. Ом Пракаш Я пробовал это раньше, но решение, похоже, глючит. Когда я использовал приведенный ниже код, VoiceOver по-прежнему сначала начинает считывать inputTextField и только через некоторое время переключается и начинает считывать мой индикатор выполнения. В настоящее время у меня есть обходной путь, позволяющий скрыть текстовое поле от голоса за кадром ‘otpNumberTextField.accessibilityElementsHidden = true’, а затем использовать функцию, чтобы отобразить его через 5 секунд. Таким образом, VoiceOver сначала начнет считывать индикатор выполнения. Также обратите внимание, что эта ошибка возникает только тогда, когда предыдущий VC был сфокусирован на другом поле ввода (не возникает для VC, последний активный фокус которого был на кнопке).