我正在开发一个可以播放列表中显示的音频文件的应用程序。
音频文件1
音频文件2
...
音频文件10
我有使用以下代码的音频。
var audioPlayer: AVAudioPlayer?
func playSound1() {
let path = Bundle.main.path(forResource: "audiofile1.mp3", ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer?.play()
} catch {
print("Could not find file")
}
}
struct ContentView: View {
var body: some View {
Button(action:{ playSound1()}) {
Text("Audio File 1") }
}
}
我正在寻找解决方案,当第二次点击音频文件 1 时,它将停止播放音频文件 1。此外,如果音频文件 1 正在播放,并且在音频文件 2 上点击一下,则会停止播放音频文件 1 并播放音频文件 2。希望所有 10 个音频文件都发生这种情况。
我建议如下:
class AudioModel: ObservableObject {
var audioPlayer: AVAudioPlayer?
@Published var current: String = ""
var audioFiles = ["audiofile1.mp3", "audiofile2.mp3", "audiofile3.mp3"]
func playSound() {
let path = Bundle.main.path(forResource: self.current, ofType:nil)!
let url = URL(fileURLWithPath: path)
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer?.play()
} catch {
print("Could not find file")
}
}
func stopSound() {
// Stop AVAudioPlayer
// audioPlayer.stop() ???
}
}
struct ContentView: View {
@ObservedObject var audioModel = AudioModel()
var body: some View {
VStack {
ForEach(self.audioModel.audioFiles, id: \.self) { item in
Button(action:{
self.audioModel.current = item
}) {
Text(item)
}
}
}
}.onReceive(self.audioModel.$current) {_ in
self.audioModel.stopSound()
self.audioModel.playSound()
}
}
尚未完成,因为我无法测试它,但我希望这有助于进一步调查。
@Published
与 @State
类似,还创建了一个 Publisher,因此每当更新时,都会进行 onReceive()
调用。这是通过使用 @ObservedObject
装饰器“观察”对象来实现的,该装饰器只能应用于符合 ObservableObject
的类
import AVFoundation
// Audio Model
final class AudioModel: ObservableObject {
@Published var current = ""
static let shared = AudioModel()
private init() {}
var audioPlayer: AVAudioPlayer?
var audioFiles = ["audiofile1.mp3", "audiofile2.mp3", "audiofile3.mp3"]
func playSound() {
let path = Bundle.main.path(forResource: current, ofType: nil)!
let url = URL(fileURLWithPath: path)
do {
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer?.play()
} catch {
print("Could not find file")
}
}
func stopSound() {
// Stop AVAudioPlayer
audioPlayer?.stop()
}
}
// Usage example
struct ContentView: View {
@StateObject var audioModel = AudioModel.shared
var body: some View {
VStack {
ForEach(audioModel.audioFiles, id: \.self) { item in
Button {
play(item)
} label: {
Text(item)
}
}
}
}
private func play(_ track: String) {
audioModel.current = track
audioModel.stopSound()
audioModel.playSound()
}
}