[英]Keep AVSpeechSynthesizer playing if another view is presented modally
我正在嘗試在 swift/xcode 中利用 AVSpeechSynthesizer 來讀出一些文本。 我大部分時間都在工作。 我已經設置好了,如果他們回到上一個屏幕或下一個屏幕,音頻將停止。 但在我的例子中,如果以模態呈現另一種觀點,我希望演講繼續。 例如,我有一個退出按鈕,點擊后會顯示“您確定要退出嗎?是/否”類型的屏幕,但我希望音頻繼續播放,直到他們單擊是並被帶走。 我還有另一個可以模態呈現的視圖,如果是這種情況,我希望音頻繼續。
有沒有人知道如何在視圖以模態顯示在頂部時保持語音播放,但在完全導航到另一個視圖時停止播放?
到目前為止,這是我的代碼:
//Press Play/Pause Button
@IBAction func playPauseButtonAction(_ sender: Any) {
if(isPlaying){
//pause
synthesizer.pauseSpeaking(at: AVSpeechBoundary.immediate)
playPauseButton.setTitle("Play", for: .normal)
} else {
if(synthesizer.isPaused){
//resume playing
synthesizer.continueSpeaking()
} else {
//start playing
theUtterance = AVSpeechUtterance(string: audioTextLabel.text!)
theUtterance.voice = AVSpeechSynthesisVoice(language: "en-UK")
synthesizer.speak(theUtterance)
}
playPauseButton.setTitle("Pause", for: .normal)
}
isPlaying = !isPlaying
}
//Press Stop Button
@IBAction func stopButtonAction(_ sender: Any) {
if(isPlaying){
//stop
synthesizer.stopSpeaking(at: AVSpeechBoundary.immediate)
playPauseButton.setTitle("Play", for: .normal)
isPlaying = !isPlaying
}
}
//Leave Page
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
synthesizer.stopSpeaking(at: .immediate)
}
問題在於您的viewWillDisappear
。 任何類型的新屏幕都會觸發此操作,因此您的代碼確實會被調用synthesizer.stopSpeaking(at: .immediate)
,從而停止您的音頻。 這包括演示或推送新的控制器。
現在,如何改進? 你提到過這個:
我已經設置好了,如果他們回到上一個屏幕或下一個屏幕,音頻將停止
首先,如果他們回到上一個屏幕:
您希望在deinit { }
方法中執行相同的音頻代碼行停止。 這會讓您知道您的屏幕或控制器正在從內存中刪除,這意味着控制器在您的控制器堆棧中消失了(用戶返回到上一個屏幕)。 只要您沒有保留周期計數問題,這應該可以 100% 正常工作。
接下來,到下一個屏幕,您可以輕松地在函數中包含停止音頻的相同代碼行以推送新屏幕。
經過大量研究,我能夠獲得所需的功能。 正如格倫所建議的那樣,正確的方法是在deinit
而不是viewWillDisappear
調用deinit
。 問題是使用AVSpeechSynthesizer
/ AVSpeechSynthesizerDelegate
通常會創建對 ViewController 的強引用,因此不會調用 deinit。 為了解決這個問題,我必須創建一個從AVSpeechSynthesizerDelegate
繼承的自定義類,但使用對自定義協議的弱委托引用。
自定義類和協議:
import UIKit
import AVFoundation
protocol AudioTextReaderDelegate: AnyObject {
func speechDidFinish()
}
class AudioTextReader: NSObject, AVSpeechSynthesizerDelegate {
let synthesizer = AVSpeechSynthesizer()
weak var delegate: AudioTextReaderDelegate!
//^IMPORTANT to use weak so that strong reference isn't created.
override init(){
super.init()
self.synthesizer.delegate = self
}
func startSpeaking(_ toRead: String){
let utterance = AVSpeechUtterance(string: toRead)
synthesizer.speak(utterance)
}
func resumeSpeaking(){
synthesizer.continueSpeaking()
}
func pauseSpeaking(){
synthesizer.pauseSpeaking(at: .immediate)
}
func stopSpeaking() {
synthesizer.stopSpeaking(at: .immediate)
}
func speechSynthesizer(_ synthesizer: AVSpeechSynthesizer, didFinish utterance: AVSpeechUtterance) {
self.delegate.speechDidFinish()
}
}
然后在我的 ViewController 中繼承和使用它:
import UIKit
import AVFoundation
class MyClassViewController: UIViewController, AudioTextReaderDelegate{
var isPlaying = false
let audioReader = AudioTextReader()
let toReadText = "This is the text to speak"
@IBOutlet weak var playPauseButton: UIButton!
@IBOutlet weak var stopButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
self.audioReader.delegate = self
}
//Press Play/Pause Button
@IBAction func playPauseButtonAction(_ sender: Any) {
if(isPlaying){
//Pause
audioReader.synthesizer.pauseSpeaking(at: .immediate)
playPauseButton.setTitle("Play", for: .normal)
} else {
if(audioReader.synthesizer.isPaused){
//Resume Playing
audioReader.resumeSpeaking()
} else {
audioReader.startSpeaking(toReadText)
}
playPauseButton.setTitle("Pause", for: .normal)
}
isPlaying = !isPlaying
}
//Press Stop Button
@IBAction func stopButtonAction(_ sender: Any) {
if(isPlaying){
//Change Button Text
playPauseButton.setTitle("Play", for: .normal)
isPlaying = !isPlaying
}
//Stop
audioReader.stopSpeaking()
}
//Finished Reading
func speechDidFinish() {
playPauseButton.setTitle("Play", for: .normal)
isPlaying = !isPlaying
}
//Leave Page
deinit {
audioReader.stopSpeaking()
playPauseButton.setTitle("Play", for: .normal)
isPlaying = !isPlaying
}
@IBAction func NextStopButton(_ sender: Any) {
audioReader.stopSpeaking()
playPauseButton.setTitle("Play", for: .normal)
isPlaying = !isPlaying
}
}
我希望這對未來的人有所幫助,因為這讓我難以自拔。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.