假设 iOS 应用程序通过
overlay
修饰符或在 ZStack
中呈现一些内容。通过这种方式,可访问性焦点(例如,当用户启用语音时)可用于父内容和呈现内容的元素。
我可以在底层视图上使用
accessibilityHidden(isOverlayPresented)
修饰符来解决此问题,但在这种情况下,当 isOverlayPresented
为 false
时,SwiftUI 会忽略传递给应用于子视图的 accessibilityHidden
修饰符的参数。
在下面的示例中,当显示“文本 3”时,可访问性转子会忽略“文本 1”和“文本 2”标签,但当未显示“文本 3”时,它不会忽略“文本 1”,尽管应用了
.accessibilityHidden(true)
.
struct ContentView: View {
@State var isOverlayPresented = false
var body: some View {
VStack(spacing: 40) {
ZStack {
VStack(spacing: 20) {
Text("Text 1")
.accessibilityHidden(true)
Text("Text 2")
}
// don't want the view to be accessible when overlay is presented
.accessibilityHidden(isOverlayPresented)
if isOverlayPresented {
Text("Text 3")
.padding(30)
.background(.yellow)
}
}
Button(isOverlayPresented ? "Show" : "Hide") {
isOverlayPresented.toggle()
}
.buttonStyle(.bordered)
}
}
}
在我看来,“文本 1”总是被可访问性忽略应该是预期的行为。如果我在 SwiftUI 环境中实现这一点,我会做类似的事情,这样从父级传递的
true
值就无法覆盖子级首选项。
extension View {
func accessibilityHidden(_ hidden: Bool) -> some View {
transformEnvironment(\.accessibilityHidden) { hiddenByParent in
hidden = hidden || hiddenByParent
}
}
}
我还可以使用条件修饰符,当参数值为 false 时不会应用它,但在我看来条件修饰符是邪恶的,特别是当应用于复杂视图时(例如某些流程的根视图)。
有什么好的方法可以实现我想要的吗?
由于您将accessibilityHidden应用于容器,它会重写您应用于Text(“Text1”)的内部修饰符,并且因为当未显示Text3的背景时
isOverlayPresented == false
,因此第.accessibilityHidden(isOverlayPresented)
行表示所有VStack的子级都不应该隐藏可达性。
发生这种情况是因为容器默认不是可访问元素。所以你需要指定它们是
要实现此目的,您需要在
.accessibilityElement(children: .contain)
之前应用.accessibilityHidden(isOverlayPresented)
。这样我们就知道 VStack 是可访问元素,并且它包含它的子元素,因此我们可以与它们交互
代码如下:
struct ContentView: View {
@State var isOverlayPresented = false
var body: some View {
VStack(spacing: 40) {
ZStack {
VStack(spacing: 20) {
Text("Text 1")
.accessibilityHidden(true)
Text("Text 2")
}
// ====
// ==== You need to add this line ====
// ====
.accessibilityElement(children: .contain)
// don't want the view to be accessible when overlay is presented
.accessibilityHidden(isOverlayPresented)
if isOverlayPresented {
Text("Text 3")
.padding(30)
.background(.yellow)
}
}
Button(isOverlayPresented ? "Show" : "Hide") {
isOverlayPresented.toggle()
}
.buttonStyle(.bordered)
}
}
}