我在VoiceOver遇到了一个奇怪的问题。
目标:
UIStackView
的UILabel
作为我的navigationItem.titleView
。accessibilityLabel
设置为适当的值。UIAccessibility.post(notification: .screenChanged, argument: navigationItem.titleView)
中调用viewDidAppear(animated:)
,将堆栈视图设置为初始VoiceOver焦点。预期结果:
实际结果:
如果我将navigationItem.titleView
设置为UILabel
的实例,则不会发生此问题。
有谁知道为什么会这样?这是iOS中的错误吗?
我已经建立了一个简单的项目来证明这个问题:https://github.com/rzulkoski/Focus-TitleView-Bug
您第二次阅读标题的原因在于您的代码。
在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用户不会自然地猜测标题之前存在另一个元素:
从技术上讲,你的问题是用上面的代码解决的,但从概念上讲,如果你仍然希望将标题作为第一个元素公开,我建议重新排序你的元素。
==========
编辑(解决方法)
关于技术问题,您的评论正确,上述解决方案的工作归功于VoiceOver的标签阅读。
我在你的初始帖子中给你的git分支提交了一个解决方案。
问题涉及UIStackView我在这种情况下无法解释,也无法解决。
为了达到你的目的,我为stackview创建了一个UIAccessibilityELement
,可以完美地实现并且没有双重读取和后期通知。
我这样做是因为当标签出现时,我无法以编程方式获得stackview新大小...可能创建一个UIStackView子类并进入其layoutSubviews
可能是诀窍?
此解决方案应该作为一种解决方法,但我不知道UIStackview出现此行为的原因。
==========
编辑(解决方案)
问题是titleView
的navigationItem
的创建方式。实现目标的最佳方法是:
UIView
,其框架与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
}()
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读出一次作为屏幕的第一个元素。