当关注非uilabel标题视图时,VoiceOver读取可访问性标签两次



我正在遇到Voiceover的奇怪问题。

目标:

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

预期结果:

  • 当视图控制器出现时,焦点似乎在标题视图上,而Voiceover一次读取可访问性标签的内容。

实际结果:

  • 配音开始读取可访问性标签的内容,然后逐步读取(或有时完成后),它将第二次阅读。

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

有人知道为什么会发生这种情况吗?是iOS中的错误吗?

我已经设置了一个简单的项目,在此处证明了问题:https://github.com/rzulkoski/focus-titleview-bug

您第二次阅读标题的原因是在代码中。

viewDidLoad中,您设置了VoiceOver自动读取以告知用户更改的StackView可访问性标签。

接下来,您在viewDidAppear中的帖子中通知此更改自然也可以读出。

为了防止这种行为,只需在 setupNavigationItem函数中删除 stackView.accessibilityLabel = label.text,然后在私人懒惰var标签init中添加此片段:

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

更新stackView.accessibilityLabel这种方式不会触发配音以告知用户并允许您获得目的。

但是,我不建议将标题读取为新页面的第一个元素,除非您重新排序呈现的元素。

Voiceover用户自然不会猜测标题之前存在另一个元素:

  • 他们可能找不到回到上一页的方法。
  • 如果他们以4个手指的简单敲击获得页面的第一个元素,因为他们将获得后退按钮而不是标题。

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

===========

编辑(解决方法)

关于技术问题,您的评论是正确的,由于Voiceover的标签阅读。

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

问题涉及我在这种情况下无法解释的uistackView,也无法解决。

为了达到您的目的,我为stackView创建了一个UIAccessibilityELement,可以完美地触及并没有双重阅读,并通过注释后。

我这样做是因为我无法以编程方式获得标签中的stackView新尺寸...也许创建一个UistackView子类并进入其layoutSubviews可能是技巧吗?

此解决方案应作为解决方法,但我不知道为什么使用UistackView出现此行为的原因。

===========

编辑(解决方案)

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

  • 将您的标题视图初始化为简单的UIView,其帧与StackView相同。
  • 在指定了其框架及其可访问性属性后,将stackView添加为子视图。

按照您的代码中的以下步骤:

  • 在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
    }()
    
  • 在您的"开关...案例..."代码部分中更改stackView案例:

    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 仅读出您的stackView 作为屏幕的第一个元素。

最新更新