bra*_*ith 11 ios voiceover uiaccessibility
在 iOS 中使用 Voice Over 时,调用UIAccessibility.post(notification:argument:)来宣布字段错误实际上并不会宣布错误。
我有一个提交按钮,当聚焦按钮时,旁白会如你所愿读取按钮标题。按下按钮时,画外音会再次朗读标题。当提交按钮被按下时,我正在做一些验证,当出现字段错误时,我试图通过调用来宣布它:
if UIAccessibility.isVoiceOverRunning {
UIAccessibility.post(notification: .announcement, argument: "my field error")
}
Run Code Online (Sandbox Code Playgroud)
有趣的是,如果我在调试器的断点处停下来,就会发生通知。当我不在断点处停止时,公告不会发生。
通知发布在主线程上,如果是这样NotificationCenter.default,我假设它是在发布的同一线程上处理的。我试图将调用分派到主队列,即使它已经在主线程上,但这似乎也不起作用。
我唯一能想到的是在旁白完成阅读提交按钮标题之前发布和观察通知,并且公告通知不会中断当前的旁白。
我真的很感激这方面的任何帮助。
ted*_*ock 10
这是一个公认的hacky解决方案,但我能够通过稍微延迟调度到主线程来防止系统公告抢占我自己的:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
UIAccessibility.post(notification: .announcement, argument: "<Your text>")
}
Run Code Online (Sandbox Code Playgroud)
另一种解决方法是使用 .screenChanged 并传递错误标签,如下所示:
UIAccessibility.post(notification: .screenChanged, argument: errorLabel)
Run Code Online (Sandbox Code Playgroud)
小智 5
我面临着同样的问题,所以我采用了 @brandenesmith 的通知队列想法并编写了一个小帮助器类。
class AccessibilityAnnouncementQueue {
static let shard = AccessibilityAnnouncementQueue()
private var queue: [String] = []
private init() {
NotificationCenter.default.addObserver(self,
selector: #selector(announcementFinished(_:)),
name: UIAccessibility.announcementDidFinishNotification,
object: nil)
}
func post(announcement: String) {
guard UIAccessibility.isVoiceOverRunning else { return }
queue.append(announcement)
postNotification(announcement)
}
private func postNotification(_ message: String) {
let attrMessage: NSAttributedString = NSAttributedString(string: message, attributes: [.accessibilitySpeechQueueAnnouncement: true])
UIAccessibility.post(notification: .announcement, argument: attrMessage)
}
@objc private func announcementFinished(_ sender: Notification) {
guard
let userInfo = sender.userInfo,
let firstQueueItem = queue.first,
let announcement = userInfo[UIAccessibility.announcementStringValueUserInfoKey] as? String,
let success = userInfo[UIAccessibility.announcementWasSuccessfulUserInfoKey] as? Bool,
firstQueueItem == announcement
else { return }
if success {
queue.removeFirst()
} else {
postNotification(firstQueueItem)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我可以使用重试机制来使其工作,在该机制中我注册为观察者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!)
}
}
Run Code Online (Sandbox Code Playgroud)
问题是,这个重试机制将始终被使用,因为第一次调用总是UIAccessibility.post(notification: .announcement, argument: _errors.first!)(除非我在断点处停止)。我还是不明白为什么第一篇文章总是失败。
| 归档时间: |
|
| 查看次数: |
6482 次 |
| 最近记录: |