【问题标题】:How to set focus on second Accessibility element?如何将焦点放在第二个辅助功能元素上?
【发布时间】:2025-01-05 14:50:01
【问题描述】:

我尝试将焦点设置到警报视图上的第二个元素:

 UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, secondElement);

它适用于 iOS 12 及之前版本,但在 iOS 13 之后,焦点最初会放在第二个元素上,但很快就会放在第一个元素上。

【问题讨论】:

    标签: ios objective-c accessibility voiceover uiaccessibility


    【解决方案1】:

    有时,当出现新视图时,您的发布通知与系统发布的通知之间存在一些竞争。您可能需要延迟通知,这有点小技巧,但通常可以。

    如果您要打开警报,我认为您想发布UIAccessibilityLayoutChangedNotificationscreenChangedlayoutChanged 通知类型之间的区别相对较小——它们都会导致 VoiceOver 刷新其在屏幕上与之交互的缓存——但它们的默认行为有所不同。

    screenChanged 通知应在出现全新屏幕时触发,它会导致焦点移动到新屏幕上的第一个可聚焦元素。

    layoutChanged 通知应该在当前屏幕的一部分发生变化时触发,例如切换展开-折叠面板,但默认情况下它不会将焦点移至元素。如果您愿意,您可以提供接收焦点的元素作为layoutChanged 通知的第二个参数。

    在 Swift 中,这可能看起来像:

    if UIAccessibility.isVoiceOverRunning {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            UIAccessibility.post(notification: .layoutChanged, argument: secondElement)
        }
    }
    

    在目标 C 中:

    if (UIAccessibilityIsVoiceOverRunning()) {
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.0) {
            UIAccessibilityPostNotification(
                UIAccessibilityLayoutChangedNotification,
                secondElement);
        }
    }
    

    重要提示: 小心以这种方式改变焦点。在打开警报时,可能可以接受以这种方式更改焦点,但是您必须测试以确保警报的内容在打开时由 VoiceOver 实际宣布它同时使用这种技术。 VoiceOver 用户可能会错过该消息。一般来说,设置一个意想不到的焦点位置可能会给依赖此类软件的人带来更多的问题。

    【讨论】:

    • 我实际上已经尝试过了,但它并不总是有效。我的警报被放置在自定义 UIWindow 上。 iOS 13 之后出现了很多问题,比如当我从 WKWebview 调用 alert 时,焦点往往不在屏幕上的任何位置,而是读取第一个元素的内容。你知道为什么吗?你知道如何准确地将焦点放在元素上吗?
    • 对了,为什么要使用 UIAccessibilityLayoutChangedNotification?它们有什么区别?
    • 我将用screenChangedlayoutChanged 的详细信息更新我的答案。
    • 听起来仍然像一个较低级别的通知覆盖了您发布的通知,导致 VoiceOver 的焦点根据默认行为设置,即关注第一个元素。如果您触发 layoutChanged 而不是 screenChanged,它应该会阻止此较低级别的通知覆盖您的通知。
    • 我按照你说的改了layoutChanged,但是还是把重点放在了第一个元素上,真是奇怪。此外,使用layoutChanged 很有可能专注于元素而不是广播它。你知道为什么吗?