Почему UIAccessibility.post (уведомление: .announcement, аргумент: "arg") не объявляется голосом за кадром? - PullRequest
1 голос
/ 04 апреля 2019

При использовании Voice Over в iOS вызов UIAccessibility.post(notification:argument:) для объявления ошибки поля фактически не объявляет ошибку.

У меня есть кнопка отправки, и при ее фокусировке голос за кадром читает заголовок кнопки, как и следовало ожидать. При нажатии кнопки голос за кадром снова читает заголовок. Когда кнопка отправки нажата, я выполняю некоторую проверку и, когда возникает ошибка поля, я пытаюсь объявить об этом, вызывая:

if UIAccessibility.isVoiceOverRunning {
    UIAccessibility.post(notification: .announcement, argument: "my field error")
}

Интересно, что если я остановлюсь на точке останова в отладчике, произойдет объявление. Когда я не останавливаюсь на точке останова, объявление не происходит.

Уведомление публикуется в основной ветке, и, если оно похоже на NotificationCenter.default, я предполагаю, что оно обрабатывается в той же ветке, в которой оно было размещено. Я попытался отправить вызов в основную очередь, даже если он уже находится в главном потоке, и это тоже не работает.

Единственное, о чем я могу подумать, это то, что уведомление публикуется и наблюдается до того, как голос за кадром закончится, после прочтения заголовка кнопки отправки, и уведомление об объявлении не прервет текущий голос.

Буду очень признателен за любую помощь в этом.

Обновление

Я могу заставить это работать, используя механизм повтора, где я регистрируюсь как наблюдатель UIAccessibility.announcementDidFinishNotification, а затем извлекаю объявление и статус успеха из словаря userInfo.

Если статус успеха равен false и объявление совпадает с тем, которое я только что отправил, я снова отправляю уведомление. Это повторяется до тех пор, пока объявление не будет успешным.

Очевидно, что при таком подходе существует множество проблем, в том числе необходимость отменить регистрацию, что произойдет, если другому объекту удастся опубликовать такое же объявление (это не должно происходить на практике, но теоретически это может произойти), необходимость отслеживать последнее отправленное объявление и т. д.

Код будет выглядеть так:

private var _errors: [String] = []
private var _lastAnnouncement: String = ""

init() {
    NotificationCenter.default.addObserver(
        self,
        selector: #selector(announcementFinished(_:)),
        name: UIAccessibility.announcementDidFinishNotification,
        object: nil
    )
}

func showErrors() {
    if !_errors.isEmpty {
        view.errorLabel.text = _errors.first!
        view.errorLabel.isHidden = false

        if UIAccessibility.isVoiceOverRunning {
            _lastAnnouncement = _errors.first!
            UIAccessibility.post(notification: .announcement, argument: _errors.first!)
        }
    } else {
        view.errorLabel.text = ""
        view.errorLabel.isHidden = true
    }
}

@objc func announcementFinished(_ sender: Notification) {
    guard let announcement = sender.userInfo![UIAccessibility.announcementStringValueUserInfoKey] as? String else { return }
    guard let success = sender.userInfo![UIAccessibility.announcementWasSuccessfulUserInfoKey] as? Bool else { return }

    if !success && announcement == _lastAnnouncement {
        _lastAnnouncement = _errors.first!
        UIAccessibility.post(notification: .announcement, argument: _errors.first!)
    }
}

Проблема в том, что этот механизм повтора всегда будет использоваться, потому что всегда первый вызов UIAccessibility.post(notification: .announcement, argument: _errors.first!) (если меня не остановили на точке останова). Я до сих пор не знаю, почему первый пост всегда терпит неудачу.

1 Ответ

0 голосов
/ 07 апреля 2019

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

Я написал ответ о проблемах с очередями нескольких уведомлений VoiceOver, которые могут помочь вам понять вашу текущую ситуацию.

Ваше уведомление работает с точкой останова, потому что вы ее откладываете, и система работает в это время: нет перекрытиямежду вашим уведомлением и работой системы.

Простым решением может быть реализовать небольшую задержку перед отправкой вашего уведомления .

Ваш механизм повторных попыток интеллектуален и его можно улучшитьв цикле из нескольких повторных попыток в случае многих захватов системы.

...