我正在尝试在我的应用程序上播放音乐,并设法从应用程序的设置中播放/停止音乐。
首先,我正在创建一个名为MusicPlayer
:的ObservableObject
类
class MusicPlayer: ObservableObject {
@Published var isPlaying = AppDefaults.shared.isMusicPlaying()
@Published var music : AVAudioPlayer? = nil
func playMusic() {
guard let strFilePath = Bundle.main.path(forResource: "music", ofType: "mp3") else { return }
do {
music = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: strFilePath))
} catch {
print(error)
}
music?.volume = 0.60
music?.numberOfLoops = -1
if isPlaying {
music?.play()
} else {
music?.stop()
}
}
}
然后播放主应用程序文件中的音乐:
@main
struct AppName: App {
@StateObject private var player = MusicPlayer()
var body: some Scene {
WindowGroup {
ContentsView()
.onAppear {
player.playMusic()
}
}
}
}
然后尝试使用设置中的切换来停止/播放音乐:
struct SettingsView: View {
@StateObject private var player = MusicPlayer()
var body: some View {
Toggle("Music", isOn: $player.isPlaying)
.onChange(of: player.isPlaying, perform: { _ in
AppDefaults.shared.setMusic(player.isPlaying)
if player.isPlaying {
player.music?.stop()
} else {
player.music?.play()
}
})
}
}
现在的问题是,打开或关闭并不能改变比赛的状态。如何解决此问题?
这里的问题是您要初始化Viewmodel两次。所以你有两个不同的真相来源。因此存在两种不同的CCD_ 3。
解决方案:在顶部视图中创建一个实例,并将其传递给需要此实例的视图。
由于您决定省略SettingsView
如何与其他视图关联,我只能给出一个更通用的解决方案。
假设SettingsView
用于AppName
:
@StateObject private var player = MusicPlayer()
WindowGroup {
....(ContentView stuff)
SettingsView()
// pass the observableObject on to the SettingsView and its children
.environmentObject(player)
}
然后在SettingsView
:中
struct SettingsView: View {
// get the observableObject from the environment
@EnvironmentObject private var player: MusicPlayer
var body: some View {
Toggle("Music", isOn: $player.isPlaying)
.onChange(of: player.isPlaying, perform: { _ in
AppDefaults.shared.setMusic(player.isPlaying)
if player.isPlaying {
player.music?.stop()
} else {
player.music?.play()
}
})
}
}