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

问题描述 投票:2回答:1

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

目标:

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

预期结果:

  • 当视图控制器出现时,焦点显示在标题视图上,VoiceOver会一次读取辅助功能标签的内容。

实际结果:

  • VoiceOver开始读取辅助功能标签的内容,然后部分通过(或有时在完成后)它继续读取它第二次。

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

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

我已经建立了一个简单的项目来证明这个问题:https://github.com/rzulkoski/Focus-TitleView-Bug

ios accessibility voiceover titleview
1个回答
1
投票

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

viewDidLoad中,您设置了堆栈视图可访问性标签,VoiceOver会自动读取该标签以通知用户更改。

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

要防止出现这种情况,只需删除stackView.accessibilityLabel = label.text函数中的setupNavigationItem,并将此代码段添加到私有懒惰变量标签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出现此行为的原因。

==========

编辑(解决方案)

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

  • 将titleView初始化为一个简单的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 }()
  • 更改“switch ... case ...”代码部分中的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读出一次作为屏幕的第一个元素。

© www.soinside.com 2019 - 2024. All rights reserved.