So after updating to Xcode 12.0.1 AVSpeechSynthesizer is now working on simulator (it hasn't been working for me for a while). Now, the isSpeaking variable is always false regardless of whether the synthesizer is speaking. I would like to trigger a change in my view as a function of whether the synthesizer is speaking. Simple version below, any ideas?
import SwiftUI
import AVFoundation
struct ContentView: View {
var synthesizer = AVSpeechSynthesizer()
var utterance = AVSpeechUtterance(string: "Hello World")
var body: some View {
VStack {
Text(synthesizer.isSpeaking ? "Speaking" : "Not Speaking")
Button(action: {synthesizer.speak(utterance)}) {
Text("Speak To Me")
}
}
}
}
It is just not updated in your case, because synthesiser.isSpeaking
is not observable for SwiftUI. You have to use view model class and delegate callbacks to handle this state changes
Here is initial demo (you can add stop/pause/continue actions by yourself)
class SpeachViewModel: NSObject, ObservableObject, AVSpeechSynthesizerDelegate {
@Published var isSpeaking = false
private var synthesizer = AVSpeechSynthesizer()
override init() {
super.init()
synthesizer.delegate = self
}
deinit {
synthesizer.delegate = nil
}
func speak(_ utterance: AVSpeechUtterance) {
self.synthesizer.speak(utterance)
}
// MARK: AVSpeechSynthesizerDelegate
internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didStart utterance: AVSpeechUtterance) {
self.isSpeaking = true
}
internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
self.isSpeaking = false
}
internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didPause utterance: AVSpeechUtterance) {
self.isSpeaking = false
}
internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didCancel utterance: AVSpeechUtterance) {
self.isSpeaking = false
}
internal func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didContinue utterance: AVSpeechUtterance) {
self.isSpeaking = true
}
}
struct ContentView: View {
@ObservedObject var vm = SpeachViewModel()
var utterance = AVSpeechUtterance(string: "Hello World")
var body: some View {
VStack {
Text(vm.isSpeaking ? "Speaking" : "Not Speaking")
Button(action: {vm.speak(utterance)}) {
Text("Speak To Me")
}
}
}
}