UIStackView辅助功能-在默认的accessibleElements中插入辅助功能视图



现在了解到UIStackView的可访问性在默认情况下会在画外音打开时按顺序读取排列的子视图。假设我有这样的层次结构:

UIView
- UIStackView
-view1
-view2
-view3
-view4
- collapsibleSpecialView

collapsibleSpecialView固定在视图4:的顶部

etc
|------------------|
|      view3       |
|------------------|
|    collapsible   |     <- when collapsed overlaps with vw3 to vw1
|------------------|
|      view4       |
|------------------|

我需要画外音来按照上面的顺序阅读我的元素。但由于stackView需要首先完成所有可访问的子视图,所以我的可折叠视图是最后读取的,但我需要在视图4之前读取。

我不能把它添加到stackview中,因为当collapsableView崩溃时,它会把上面的所有东西都推上去。我不想绕过自动布局来解决这个问题。

我认为可以在view4之前插入一个不可见的代理UIView,这样ProxyView就会覆盖其方法以返回可访问的元素。

public class ProxyView: UIView {
private var view: UIView?
/// view is the collapsibleView
@objc public convenience init(view: UIView) {
self.init()
self.isAccessibilityElement = true
self.view = view
}
public override func accessibilityElementCount() -> Int {
return 1
}
public override func accessibilityElement(at index: Int) -> Any? {
guard let menu = view else { return nil }
return menu
}
public override func index(ofAccessibilityElement element: Any) -> Int {
return 0
}
}

有了这个画外音,可以在view4之前读取我的ProxyView,但由于某种原因,它没有进入collapsableView,向右滑动会将焦点转移到view4。

如果我对UIAccessibilityContainer的理解是正确的,那么这在理论上应该有效,但事实并非如此。我错过了什么?感谢

我能够解决这个问题。我的解决方案与上面的解决方案基本相同,并进行了一些修复。

class CollapsibleView: UIView {
/// set isAccessibilityElement = true in init

/// set it accessibilityElements in order you want
/// this is to tell the  VoiceOver not to capture 
/// our subviews because we are going to pass them to our proxy
/// setting this to false will cause VO to loop back to 
/// this view's subviews.    
}
class ProxyView: UIView {
var lastFocusedElement: Any?

private var view: CollapsibleView!

/// Collapsible view is accessible element and so VO will still focus on it. We pass the focus to last focused element since we want view before collapsibleView be the last focuseable element.
/// If you have other views to focus after your view, you have to figure out how to tell VO to skip collapsibleView without setting its isAccessibilityElement to false
@objc func voFocused(notification: Notification) {
guard let focused = notification.userInfo?[UIAccessibility.focusedElementUserInfoKey] else {
return
}
if let asView = focused as? UIView, asView == view {
///change focus to last
UIAccessibility.post(notification: .screenChanged, argument: lastFocusedElement)
} else {
lastFocusedElement = focused
}
}
required init?(coder: NSCoder) {
super.init(coder: coder) 
/// This is an invisible container-only view. We
/// It needs to be set to false to allow VO
/// Recognize it as a container. 
self.isAccessibilityElement = false
NotificationCenter.default.addObserver(self, selector: #selector(voFocused(notification:)),
name: UIAccessibility.elementFocusedNotification,
object: nil)
}

func setView(vw: CollapsibleView){
self.view = vw
self.accessibilityElements = view.accessibilityElements
}
}

剩下的就是将ProxyView((添加到堆栈中,按照我们想要的顺序进行它宣布的

最新更新