ios - 聚焦非 UILabel titleView 时,VoiceOver 会读取辅助功能标签两次

标签 ios accessibility voiceover titleview

我在使用 VoiceOver 时遇到了一个奇怪的问题。

目标:

  • 设置一个包含多个 UILabelUIStackView 作为我的 navigationItem.titleView
  • 将堆栈 View 标记为可访问性元素并将其 accessibilityLabel 设置为适当的值。
  • 通过在 viewDidAppear(animated:) 中调用 UIAccessibility.post(notification: .screenChanged, argument: navigationItem.titleView) 将堆栈 View 设置为初始 VoiceOver 焦点。

预期结果:

  • 当 View Controller 出现时,焦点似乎位于标题 View 上,并且 VoiceOver 会读取辅助功能标签的内容一次。

实际结果:

  • VoiceOver 开始朗读无障碍标签的内容,然后中途(或有时在读完之后)继续朗读第二遍。

如果我将 navigationItem.titleView 设置为 UILabel 的实例,则不会发生此问题。

有人知道为什么会这样吗?这是 iOS 中的错误吗?

我在这里建立了一个简单的项目来演示这个问题: https://github.com/rzulkoski/Focus-TitleView-Bug

最佳答案

你的标题有二次阅读的原因在你的代码中。

在您的 viewDidLoad 中,您设置了 VoiceOver 自动读出的堆栈 View 可访问性标签,以通知用户更改。

接下来,您通过 viewDidAppear 中的帖子通知此更改,VoiceOver 自然也会读出。

要防止这种行为,只需删除 setupNavigationItem 函数中的 stackView.accessibilityLabel = label.text 并将此代码段添加到您的私有(private)惰性变量标签 init 中:

if (self.view.subviews.contains(stackView)) {
        stackView.accessibilityLabel = label.text
}

以这种方式更新 stackView.accessibilityLabel 不会触发 VoiceOver 来通知用户并允许实现您的目的。

但是,我不建议将标题读出作为新页面的第一个元素,除非你 reorder呈现的元素。

VoiceOver 用户自然不会猜到标题前有另一个元素:

  • 他们可能找不到返回上一页的方法。
  • 如果他们获得带有 4 fingers simple-tap 的页面的第一个元素,他们可能会丢失因为他们会得到后退按钮而不是标题。

从技术上讲,您的问题已通过上面的代码解决,但从概念上讲,如果您仍想将标题显示为第一个元素,我建议您对元素重新排序。

==========

编辑(解决方法)

关于技术问题,您的评论是正确的,由于 VoiceOver 的标签阅读,上述解决方案有效。

我在您在初始帖子中提供的 git 分支中提交了一个解决方案。

问题涉及 UIStackView,在这种情况下我无法解释,也无法按原样解决。

为了达到您的目的,我为 stackview 创建了一个 UIAccessibilityELement,它可以完美地访问和公开,无需通过后通知进行双重读取。

我这样做是因为当标签位于时我无法以编程方式获得 stackview 的新大小...也许创建一个 UIStackView 子类并进入其 layoutSubviews 可能是诀窍?

此解决方案应该作为变通方法但我不知道此行为出现在 UIStackview 中的原因。

==========

编辑(解决方案)

问题在于 navigationItemtitleView 的创建方式。实现目标的最佳方式是:

  • 将您的 titleView 初始化为一个简单的 UIView,其框架与 stackview 的框架相同。
  • 在指定其框架及其可访问性属性后,将堆栈 View 添加为 subview 。

在您的代码中执行以下步骤:

  • 在 stackview 属性中添加 .header 特征:

    private lazy var stackView: UIStackView = {
        let stackView = UIStackView(frame: .zero)
        stackView.axis = .vertical
        stackView.alignment = .center
        stackView.distribution = .equalSpacing
        stackView.isAccessibilityElement = true
        stackView.accessibilityTraits = .header
        return stackView
    }()
    
  • 如下更改“switch...case...”代码部分中的 stackview case:

    case .stackView:
        label.text = "UIStackView"
        label.sizeToFit()
        stackView.addArrangedSubview(label)
    
        label2.text = subtitle
        label2.sizeToFit()
        stackView.addArrangedSubview(label2)
    
        stackView.frame.size.width = max(label.frame.width, label2.frame.width)
        stackView.frame.size.height = label.frame.height + label2.frame.height
    
        stackView.accessibilityLabel = label.text?.appending(", \(label2.text!)")
    
        navigationItem.titleView = UIView(frame: stackView.frame)
        navigationItem.titleView?.addSubview(stackView)
    }
    

现在,postNotification 只读出一次堆栈 View 作为屏幕的第一个元素。

关于ios - 聚焦非 UILabel titleView 时,VoiceOver 会读取辅助功能标签两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54954861/

相关文章:

html - NG-SELECT 在 Safari 中存在下拉列表项的可访问性问题

ios - Voiceover 使用 UIAccessibilityPostNotification 有巨大的停顿

ios - UILocalNotification 和 applicationIconBadgeNumber 的良好模式

ios - AudioUnit inputCallback with AudioUnitRender -> audioBufferList.mBuffers[0].mDataByteSize != inNumberFrames 之间不匹配

ios - Objective-C : Separate words in a string and join again

Angular CDK A11y 焦点陷阱模式/对话框

modal-dialog - 如果焦点陷阱阻止用户访问上下文 UI,例如浏览器?

iphone - 在更新到iOS 6之后,所有“取消”按钮都无法在sharekit中使用

user-interface - 桌面应用程序的可用性和可访问性

ios - 有什么方法可以禁用 UITextField 中占位符文本的辅助功能画外音吗?