在iOS中使用Voice Over时,调用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!)
(除非我在断点处停止)。我仍然不知道为什么第一篇文章总是失败。
您的问题可能会发生,因为系统需要在出现字段错误时接管,在这种情况下,任何自定义的VoiceOver通知都会被取消。
我写了一篇关于排队多个VoiceOver通知问题的answer,可以帮助您了解当前的情况。
您的通知使用断点,因为您在此期间延迟它并且系统正常工作:您的通知和系统工作之间没有重叠。
一个简单的解决方案可能是在发送通知之前实施短暂延迟。
您的重试机制很聪明,在很多系统接管的情况下,可以在少量重试的循环内进行改进。