Reputation: 568
I'm trying to make an App that simulates the behavior of Calculator app from Apple. On the Calculator, when you tap = (Equals), the App reads "Result, Number.", from the main display view. How can I reproduce this behavior in SwiftUI ?
My Test Scenario:
struct ContentView: View {
@State var result = 0
var body: some View {
VStack {
Text("\(result)")
.font(.largeTitle)
.frame(height: 100)
.padding()
Spacer()
Button(action: {
self.result += 1
}, label: {
Text("Add one")
.font(.title)
.padding()
})
Button(action: {
self.result -= 1
}, label: {
Text("Minus one")
.font(.title)
.padding()
})
}
}
}
I want every time result changes, from the interaction of either Add or Minus Buttons, the VoiceOver system detects the Result changes and read the Result.
Upvotes: 1
Views: 3912
Reputation: 568
Here is my final solution:
struct ContentView: View {
@State var result = 0 {
didSet {
announce(this: "\(result)")
}
}
var body: some View {
VStack {
Text("\(result)")
.font(.largeTitle)
.frame(height: 100)
.padding()
Spacer()
Button(action: {
self.result += 1
}, label: {
Text("Add one")
.font(.title)
.padding()
})
Button(action: {
self.result -= 1
}, label: {
Text("Minus one")
.font(.title)
.padding()
})
}
//.accessibility(value: Text("\(result)"))
}
private func announce(this: String) {
if UIAccessibility.isVoiceOverRunning {
UIAccessibility.post(notification: .screenChanged, argument: "The new result is \(this).")
}
}
}
The notification i'm looking for was the .screenChanged, but I'm also wanting to use the .announcement as mention by @Scriptable.
Sometimes there's a race condition you have to solve with DispatchQueue.main.asyncAfter, as mention at: Why is UIAccessibility.post(notification: .announcement, argument: "arg") not announced in voice over?
Here where I found the others notifications: Default UIAccessibilityElement after screen change
Upvotes: 0
Reputation: 54755
You can simply use the accessibility(value:)
modifier on the body of your view.
var body: some View {
VStack {
Text("\(result)")
.font(.largeTitle)
.frame(height: 100)
.padding()
Spacer()
Button(action: {
self.result += 1
}, label: {
Text("Add one")
.font(.title)
.padding()
})
Button(action: {
self.result -= 1
}, label: {
Text("Minus one")
.font(.title)
.padding()
})
}
.accessibility(value: Text("\(result)"))
}
Upvotes: 1
Reputation: 19758
You can post a notification for Voice over to announce something. But I am not familiar with SwiftUI, so not sure where would be best to place this code in your example
The code to post the notificaiton is:
if UIAccessibility.isVoiceOverRunning {
UIAccessibility.post(notification: .announcement, argument: "message to announce")
}
Maybe you can do it this way:
function announceResult() {
if UIAccessibility.isVoiceOverRunning {
UIAccessibility.post(notification: .announcement, argument: self.result)
}
}
Button(action: {
self.result += 1
announceResult()
}
Upvotes: 2