在进行无障碍适配的过程中,有一个非常烦人的问题,就是 VoiceOver 朗读控件的顺序。通常来讲,VoiceOver 会用从上到下从左到右的顺序朗读控件,但是也有一些时候会读的乱七八糟。而且还存在一些我们需要修改这一顺序来让盲人用起来更方便的情况。
StackOverFlow 中有这样一个回答,其中描述了通过 Tag 来重建 isAccessibilityElement 顺序的方法,但是这一方法并不十分靠谱。首先设置 Tag 也并不方便,而且很多时候 Tag 会被用来干其他的事情,只使用 Tag 会带来很多问题。而且这个方法似乎压根不能用,我在测试的时候发现 isAccessibilityElement 一直是空的,不知道是不是我读取时机的问题。
于是我昨天晚上研究了一阵子,找到了一个很方便的方案,也已经写在了这个问题的回答中。和 @TejAces 的回答类似,我也采用了读 subview 数组的方案,新建一个 Swift 文件,输入以下内容:
import UIKit
extension UIView {
func updateOrder(_ direction: Bool = true) {
var tempElements: [Any]? = [Any]()
let views = (direction) ? subviews : subviews.reversed()
for aView in views {
if !aView.accessibilityElementsHidden {
tempElements?.append(aView)
}
}
accessibilityElements = tempElements
}
}
class ReorderAccessibilityByStoryBoardView: UIView {
override func didAddSubview(_ subview: UIView) {
if !subview.accessibilityElementsHidden {
updateOrder()
}
}
}
复制代码
在 Storyboard 或者代码中,将你需要修改其中控件顺序的 View 的 Class 设置为 ReorderAccessibilityByStoryBoardView,接下来你只需要调整 StoryBoard 控件列表中的排列顺序,即可直接反应在 VoiceOver 中,非常方便快捷。对于从代码添加的 View,你只需要按照想要的顺序来 addSubview() 就行了。
由于 StackView 和 ScrollView 等比较特殊,如果直接在他们的父 View 上设置 Class,并不能够读到其中的内容,所以需要在文件里单独写一个 Class 来处理:
class ReorderAccessibilityByStoryBoardStackView: UIStackView {
override func didAddSubview(_ subview: UIView) {
if !subview.accessibilityElementsHidden {
updateOrder(false)
}
}
}
复制代码
之后同样按照之前的方法设置好就可以了。
你还可以在 StackOverFlow 中查看我的回答。