我有一个音量切换按钮。当我按下按钮时,会调用暂停或播放,但会出现一些淡入淡出。问题是,如果我快速按两次按钮,例如暂停然后播放,我会听到音量跳跃。此外,如果我快速调用播放,然后猛按并调用暂停,那么在播放模式下,由于延迟调用
DispatchQueue
,音频将停止。如何解决这个问题?
视图控制器:
class ViewController: UIViewController {
@objc func soundState() {
if defaults.string(forKey: "sound") == "false" {
audio.pause(volume: 0.0, duration: 3.0)
} else if defaults.string(forKey: "sound") == "true" {
audio.play(volume: 1.0, duration: 3.0)
}
}
}
音频控制器:
class Audio: NSObject, AVAudioPlayerDelegate {
var audioPlayer: AVAudioPlayer!
func loopedAudio(fileName: String, fileExtension: String) {
try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategorySoloAmbient)
try? AVAudioSession.sharedInstance().setActive(true)
let url = Bundle.main.url(forResource: fileName, withExtension: fileExtension)
do {
audioPlayer = try AVAudioPlayer(contentsOf: url!)
audioPlayer.prepareToPlay()
audioPlayer.delegate = self
audioPlayer.numberOfLoops = -1
} catch {
print("error")
}
}
func play(volume: Float, duration: Double) {
audioPlayer.volume = 0
audioPlayer.play()
audioPlayer.setVolume(volume, fadeDuration: duration)
}
func pause(volume: Float, duration: Double) {
audioPlayer.volume = 1
audioPlayer.setVolume(volume, fadeDuration: duration)
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
self.audioPlayer.pause()
}
}
}
出现您的问题是因为您的一项操作
pause
被延迟,而您的另一项操作 play
是即时的。 这意味着如果您快速改变状态,可能不再需要他们延迟行动。
解决方案是显式跟踪所需的状态,以避免不必要的延迟操作:
enum PlaybackState {
case playing
case paused
}
class Audio: NSObject, AVAudioPlayerDelegate {
var playbackState: PlaybackState = .paused
var audioPlayer: AVAudioPlayer!
func loopedAudio(fileName: String, fileExtension: String) {
try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategorySoloAmbient)
try? AVAudioSession.sharedInstance().setActive(true)
let url = Bundle.main.url(forResource: fileName, withExtension: fileExtension)
do {
audioPlayer = try AVAudioPlayer(contentsOf: url!)
audioPlayer.prepareToPlay()
audioPlayer.delegate = self
audioPlayer.numberOfLoops = -1
} catch {
print("error")
}
}
func play(volume: Float, duration: Double) {
audioPlayer.volume = 0
audioPlayer.play()
audioPlayer.setVolume(volume, fadeDuration: duration)
self.playbackState = .playing
}
func pause(volume: Float, duration: Double) {
audioPlayer.volume = 1
audioPlayer.setVolume(volume, fadeDuration: duration)
self.playbackState = paused
DispatchQueue.main.asyncAfter(deadline: .now() + duration) {
guard self.playbackState == .paused else {
return
}
self.audioPlayer.pause()
}
}
}
现在,当你的
dispatchAfter
执行时,它会首先检查是否仍然需要 pause
状态。 如果没有,它将简单地返回,并继续播放音频。