为什么UIAccessibility.post(通知:.announcement,参数:“arg”)未在声音中宣布?

问题描述 投票:1回答:1

在iOS中使用Voice Over时,调用UIAccessibility.post(notification:argument:)来声明字段错误并不会实际发布错误。

我有一个提交按钮,当聚焦按钮时,语音会按照您的预期读取按钮标题。按下按钮时,配音再次读取标题。当按下提交按钮时,我正在进行一些验证,当出现字段错误时,我试图通过调用来宣布它:

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

有趣的是,如果我在调试器中停止断点,则会发生通知。当我没有停在断点上时,宣布不会发生。

通知是在主线程上发布的,如果像NotificationCenter.default那样,我认为它是在发布的同一个线程上处理的。我试图将调用分配给主队列,即使它已经在主线程上,这似乎也没有用。

我唯一可以想到的是,在完成语音结束阅读提交按钮标题之前发布并观察通知,并且通知通知不会中断当前的语音。

我真的很感激任何帮助。

Update

我可以使用重试机制来实现这一点,我将注册为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!)(除非我在断点处停止)。我仍然不知道为什么第一篇文章总是失败。

ios voiceover uiaccessibility
1个回答
0
投票

您的问题可能会发生,因为系统需要在出现字段错误时接管,在这种情况下,任何自定义的VoiceOver通知都会被取消。

我写了一篇关于排队多个VoiceOver通知问题的answer,可以帮助您了解当前的情况。

您的通知使用断点,因为您在此期间延迟它并且系统正常工作:您的通知和系统工作之间没有重叠。

一个简单的解决方案可能是在发送通知之前实施短暂延迟。

您的重试机制很聪明,在很多系统接管的情况下,可以在少量重试的循环内进行改进。

© www.soinside.com 2019 - 2024. All rights reserved.