NEW: My new book Pro SwiftUI is out now – level up your SwiftUI skills today! >>

How can I fix Voiceover not receiving UIAccessibilityNotification?

Forums > SwiftUI

I’m hoping someone here has experience creating accessible apps. I’m attempting to update Voiceover users that something in my UI has changed, without redirecting the focus of Voiceover. From what I can tell, this is done using the UIAccesibility, which you can read about here:

https://developer.apple.com/documentation/objectivec/nsobject/uiaccessibility

Unfortunately, this documentation isn’t clear on how one would implement the functions associated with this type to accomplish what I’m trying to do, and there don’t seem to be examples/tutorials anywhere online, but the closest thing I’ve found and attempted to replicate is what I found here: https://developer.apple.com/documentation/objectivec/nsobject/uiaccessibility

This is a simplified version of what I’m doing, but I have two different views for information in a quiz game I’m making. These two views will be conditionally shown in a parent view (ParentView), based on whether or not the question has been answered.

UnansweredQuestionView is to be shown in ParentView when the question hasn’t been answered, and AnsweredQuestionView is shown when the question has been answered.

In my game, there are multiple questions presented on-screen at once, with a field at the bottom for the player to guess the answer. I want my visually-impaired players to be informed when they answer something correctly, without having to redirect Voiceover’s focus through each question to see which one has been solved. That’s why I’m trying to use a UIAccessibilityNotification. is why I

Here’s the simplified code:

Struct UnansweredQuestionView: View {
Let question: String

Var body: some View {
Text(question)
}//body
}//struct

Struct AnsweredQuestionView: View {

Let answer: String

Var body: some View {

Text(answer)

}//body
}//struct

Struct ParentView: View {
/*key in these dictionaries is the question, value is the answer*/
Var questionData = [[String: String]]()
Var currentAnswer = “”//Represents the user’s input
//some initializer that fills questionData variable

Var body: some View {

ForEach(questionData, id: \.self.value) { data in
If answer != data.value {
UnansweredQuestionView(question: data.key)
} else {
AnsweredQuestionView(data.value)
.onAppear() {
UIAccessibility.post(notification: .announcement, argument: "Solved")
}//onAppear
}//conditional
}//ForEach
}//body
}//struct

}//body

Why would this not be announcing anything to Voiceover when the view changes? }//struct



While this code is valid, Voiceover doesn’t announce anything when the view changes.

   

I don't have much experience with this. But I just watched a video that mentioned @AccessibilityFocusState and I wonder if it might be what you need. Apple Developer documentation

I would have to read into it, and try to use it myself more to really understand it. But, it seems that it allows you to move the focus to a view where a change has occured, announce to the user that the focus has moved there, and read it to the user.

But, I wonder if you could use it to do that, then use it again to shift the focus back to view where the answer is being entered, and announce to the user that the focus has moved back.

I may be misunderstanding what it is actually capable of doing. But it might be something worth looking into.

   

@darkhorsestudios - i was wondering if you could use the below logic, you have a text , in which the user enters a value, the value will obviously be entered in a TextField , what you can do is extend Binding, check for the values being entered character by character and keep matching them against any successful answer key , the moment it mateches , you can show an alert or voice over or what ever work you want like notification ...

In my sample, i check for entry in a TextFiled and when it matches the value "Vlad" , i print done, now here you can enter any logic you want ...

extension Binding {
     func checkEntry(_ completion: @escaping (Value) -> Void) -> Binding<Value> {
        Binding {
            self.wrappedValue
        } set: { newValue in
            self.wrappedValue = newValue
            completion(newValue)

        }
     }
}

struct ContentView: View {
    @State private var answerData = ""
    let answer = "Vlad"
    var body: some View {
        TextField("Enter the answer here", text: $answerData.checkEntry(check))

    }

    func check(_ val: String) {
        print(val)
        if answerData == answer {
            print("done")
        }
    }
}

   

Hacking with Swift is sponsored by Play

SPONSORED Play is the first native iOS design tool created for designers and engineers. You can install Play for iOS and iPad today and sign up to check out the Beta of our macOS app with SwiftUI code export. We're also hiring engineers!

Click to learn more about Play!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.