[英]ADA - Programmatically shifting VoiceOver focus to another SwiftUI view - compatible with IOS 13+
概述:
我很难理解如何在与 IOS 13+ 兼容的 SwiftUI 视图中正确地以编程方式转移可访问性焦点。
这意味着不幸的是,无法使用 IOS 15+ 中可用的更新的 SwiftUI 焦点管理 API。
我看到的大多数建议都类似于以下帖子:
它建议通过使用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 个结果:
在这些结果中,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.