当聚焦非UILabel titleView时,VoiceOver会读取两次可访问性标签

时间:2019-03-02 03:09:14

标签: ios accessibility voiceover titleview

我在VoiceOver上遇到一个奇怪的问题。

目标:

  • 将包含多个UIStackView的{​​{1}}设置为我的UILabel
  • 将堆栈视图标记为可访问性元素,并将其navigationItem.titleView设置为适当的值。
  • 通过在accessibilityLabel内调用UIAccessibility.post(notification: .screenChanged, argument: navigationItem.titleView),将堆栈视图设置为VoiceOver的初始焦点。

预期结果:

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

实际结果:

  • VoiceOver开始读取可访问性标签的内容,然后在读取过程的一部分(或有时在完成后)进行第二次读取。

如果我将viewDidAppear(animated:)设置为navigationItem.titleView的实例,则不会发生此问题。

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

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

1 个答案:

答案 0 :(得分:1)

第二遍阅读标题的原因在代码中。

static void Main(string[] args) { var gradeId = 1; var context = new SchoolContext(); var data = context.Grades.Include(x => x.Students.Where(how to pass gradeId here)).SingleOrDefault(); } 中,设置VoiceOver自动读取的堆栈视图可访问性标签,以将更改通知用户。

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

要防止这种情况发生,只需在viewDidAppear函数中删除stackView.accessibilityLabel = label.text并将此代码段添加到您的私有惰性var标签init中即可:

setupNavigationItem

以这种方式更新if (self.view.subviews.contains(stackView)) { stackView.accessibilityLabel = label.text } 不会触发VoiceOver通知用户,而是可以达到目的。

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

VoiceOver用户自然不会猜测标题前面是否存在另一个元素:

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

从技术上说,您的问题已通过上面的代码段解决了,但从概念上讲,如果您仍然希望将标题显示为第一个元素,则建议对元素进行重新排序。

==========

编辑(解决方法)

关于技术问题,您的评论是正确的,由于VoiceOver读取了标签,因此上述解决方案可以正常工作。

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

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

为了达到您的目的,我为stackview创建了一个stackView.accessibilityLabel,可以完美地到达该对象并暴露出来,而无需使用后通知进行双重读取。

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

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

==========

编辑(解决方案)

问题是创建layoutSubviews中的titleView的方式。实现目标的最好方法是:

  • 将您的titleView初始化为一个简单的navigationItem,其框架与stackview的框架相同。
  • 在指定其框架和可访问性属性后,将stackview作为子视图添加。

按照以下代码中的步骤进行操作:

  • 在stackview属性中添加UIView特性:

    .header
  • 在“ switch ... case ...”代码部分中更改stackview的大小写,如下所示:

    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
    }()
    

现在,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) } 仅读取一次堆栈视图作为屏幕的第一个元素。

相关问题