我在堆栈视图中有一组按钮。按下每个按钮都会播放不同的声音。我有一个单独的按钮(循环按钮(,按下时会调用loopButtonPressed
函数。我的目标是,当按下这个循环按钮时,它将循环通过这个堆栈视图中的按钮子视图,并使用soundButtonPressed
函数按顺序播放每个声音。我在下面看到了一个使用run()
函数实现的方法,该函数将每个连续函数设置为在给定时间后运行。虽然这类工作,但它不是一个很好的解决方案,因为声音文件的长度各不相同。我想可能有一种方法可以使用调度组来实现这一点,但我并不完全理解。如果我去掉run函数,它将只播放堆栈视图中最后一个按钮的声音。我正在使用AVFoundation来播放wav文件。我很感激任何建议或指示,谢谢。
func run(after seconds: Int, completion: @escaping () -> Void) {
let deadline = DispatchTime.now() + .milliseconds(seconds)
DispatchQueue.main.asyncAfter(deadline: deadline) {
completion()
}
}
@objc func loopButtonPressed(_ sender: UIButton) {
var i = 1
for case let button as UIButton in self.colorBubblesStackView.subviews {
run(after: 800*i) {
self.soundButtonPressed(sender: button)
}
i += 1
}
}
我的soundButtonPressed函数只是一个switch语句,其中每种情况都使用正确的声音文件名调用函数playSound()
。这是播放声音功能:
func playSound(_ soundFileName: String) {
guard let url = Bundle.main.url(forResource: soundFileName, withExtension: "wav") else { return }
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileType.wav.rawValue)
guard let player = player else { return }
player.play()
} catch let error {
print(error.localizedDescription)
}
}
func playSound(name: String ) {
guard let url = Bundle.main.url(forResource: name, withExtension: "mp3") else {
print("url not found")
return
}
do {
/// this codes for making this app ready to takeover the device audio
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
try AVAudioSession.sharedInstance().setActive(true)
/// change fileTypeHint according to the type of your audio file (you can omit this)
player = try AVAudioPlayer(contentsOf: url, fileTypeHint: AVFileTypeMPEGLayer3)
player?.delegate = self
// no need for prepareToPlay because prepareToPlay is happen automatically when calling play()
player!.play()
} catch let error as NSError {
print("error: (error.localizedDescription)")
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
print("finished")//It is working now! printed "finished"!
}
按照协议进行确认
class ViewController: UIViewController,AVAudioPlayerDelegate {
而不是循环添加每个按钮一个标签并从第一个标签开始100。然后,当为玩家获得的回叫完成播放时,播放带有新icremented标签的下一个文件,比如101
尝试AVQueuePlayer
一种玩家,用于按顺序播放多个项目。
@objc func loopButtonPressed(_ sender: UIButton) {
let allUrls = allSongs.compactMap { Bundle.main.url(forResource: $0, withExtension: "wav") }
let items = allUrls.map { AVPlayerItem(url: $0) }
let queuePlayer = AVQueuePlayer(items: items)
queuePlayer.play()
}