我正在遇到Voiceover的奇怪问题。
目标:
- 将包含多个
UILabel
的UIStackView
设置为我的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出现此行为的原因。
===========
编辑(解决方案)
问题是创建navigationItem
的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 }()
在您的"开关...案例..."代码部分中更改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 作为屏幕的第一个元素。