繁体   English   中英

ADA - 以编程方式将 VoiceOver 焦点转移到另一个 SwiftUI 视图 - 与 IOS 13+ 兼容

[英]ADA - Programmatically shifting VoiceOver focus to another SwiftUI view - compatible with IOS 13+

概述:

我很难理解如何在与 IOS 13+ 兼容的 SwiftUI 视图中正确地以编程方式转移可访问性焦点。

这意味着不幸的是,无法使用 IOS 15+ 中可用的更新的 SwiftUI 焦点管理 API。

我看到的大多数建议都类似于以下帖子:

iOS 更改可访问性焦点。

它建议通过使用UIAccessibility.post(notification: .screenChanged/layoutChanged) 参数来改变焦点:View)

然而,我的尝试没有成功。

我已经能够以与下面的代码相同的方式成功使用UIAccessibility.post(notification: .announcement) argument: String)并且它确实按预期宣布了刺痛。 它比 asyncAfter 计时器花费的时间要长得多(可能是 8 秒),但它似乎表明 post() 调用有点工作。

代码示例:

带有向上或向下 V 形的自定义展开/折叠,具体取决于它是展开还是折叠。

我希望能够以编程方式控制焦点在展开时的位置。 例如,我可能希望能够在打开的扩展菜单中让 VoiceOver 专注于“菜单项 3”。

我在想接近下面代码的东西可能会起作用,但是我对帖子中的参数视图是如何工作的缺乏了解,并且不确定是否有办法使用 SwiftUI 视图或者我是否需要创建一个UIKit 查看并使用 UIViewRepresentable 或使用 UIHostingController 包装它?

当前行为

展开菜单时,VoiceOver 会移至第一项。 折叠菜单时,VoiceOver 焦点会转移到最后一个文本视图。

期望的行为

当我展开菜单时,我希望能够明确地决定 VoiceOver 焦点的位置,并能够在视图出现时更多地关注特定视图

我还考虑了使用 SwiftUI/IOS 13+ 中可用工具的其他方法。 例如,我使用了accessibility(sortPriority:) 和accessibilityElement(children: .combine/.contain/.ignore)来达到预期的结果,但这些努力也被证明是不成功的。

代码搜索:

以下 GitHub 搜索目前分别产生了 10 和 13 个结果:

https://github.com/search?q=UIAccessibility.post%28notification%3A+.layoutChanged+View+%22import+swiftui%22&type=code

https://github.com/search?q=UIAccessibility.post%28notification%3A+.screenChanged+View+%22import+swiftui%22&type=code

在这些结果中,SwiftUI 视图中使用的结果使用了“nil”参数(假设将焦点转移到屏幕上的第一项)

这让我怀疑我是否真的偏离了轨道。

非常感谢任何有关如何最好地解决此问题的指导/见解!

SwiftUI 查看:

struct ExpandingMenu: View {
     @State var expanded: Bool = false

     var body: some View {
         ScrollView {
             VStack(spacing: 12) {
                 Text("Some views above the menu")
                     .accessibility(addTraits: .isStaticText)
                     .accessibility(identifier: "Some view identifier")
                 if self.expanded {
                     VStack(spacing: 12) {
                          Text("Menu Item 1")
                          Text("Menu Item 2")
                          Text("Menu Item 3")
                             .onAppear(perform: {
                                 DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) {
                                     UIAccessibility.post(notification: .screenChanged, argument: self)
                            }

                        })
                    Image(systemName: "chevron.up")
                    FullDivider()
                    Spacer()
                }
                .accessibility(addTraits: .isButton)
                .accessibility(identifier: "Menu Expanded")
                .accessibility(removeTraits: .isStaticText)
                .onTapGesture {
                    self.expanded.toggle()
                }
                } else {
                    VStack(spacing: 12) {
                        FullDivider()
                        Image(systemName: "chevron.down")
                        FullDivider()
                        Spacer()
                    }
                    .accessibility(addTraits: .isButton)
                    .accessibility(identifier: "Menu Collapsed")
                    .accessibility(removeTraits: .isStaticText)
                    .onTapGesture {
                        self.expanded.toggle()
                }
            }
            Text("Some views below the menu")
                .accessibility(addTraits: .isStaticText)
                .accessibility(identifier: "Some Text 3")
        }
    }
}

示例折叠菜单: 折叠菜单

扩展菜单示例: 扩展菜单

请尝试我的 SwiftUI / UIKit 解决方案来设置对可访问性的关注,而无需新的焦点管理 API (iOS 15+):

import SwiftUI

struct LabelFocusable: View {
    var text: String

    @State private var height: CGFloat = .zero
    
    @Binding var focused: Bool

    var body: some View {
        LabelView(text: text, dynamicHeight: $height, focused: $focused)
            .frame(minHeight: height)
                               .fixedSize(horizontal: false, vertical: true)
    }

    private struct LabelView: UIViewRepresentable {
        var text: String
        
        @Binding var dynamicHeight: CGFloat
        
        @Binding var focused: Bool

        func makeUIView(context: Context) -> UILabel {
            let label = UILabel()
            label.numberOfLines = 0
            label.lineBreakMode = .byWordWrapping
            label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
            label.font = .systemFont(ofSize: 15, weight: .bold)
            label.isAccessibilityElement = true
            label.textAlignment = .center
            return label
        }

        func updateUIView(_ uiView: UILabel, context: Context) {
            uiView.text = text
            
            DispatchQueue.main.async {
                dynamicHeight = uiView.sizeThatFits(CGSize(width: uiView.bounds.width, height: CGFloat.greatestFiniteMagnitude)).height
            }
            
            if focused {
                DispatchQueue.main.async {
                    focused = false
                    
                    UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: uiView)
                }
            }
        }
    }
}

例子:

import SwiftUI

struct ContentView: View {
    
    @State private var label1Focused = false
    
    @State private var label2Focused = false
    
    var body: some View {
        VStack(spacing: 64) {
            Text("Headline")
                .font(.largeTitle)
            
            LabelFocusable(text: "Label 1", focused: $label1Focused)       
            
            LabelFocusable(text: "Label 2", focused: $label2Focused)

            Button {
                label1Focused = true
            } label: {
                Text("Focus Label 1")
            }
            .buttonStyle(.borderedProminent)
            
            Button {
                label2Focused = true
            } label: {
                Text("Focus Label 2")
            }
            .buttonStyle(.borderedProminent)
        }
        .padding(.horizontal)
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM