AVFoundation音频播放器仅停止时响应滑块音量,如何实现拖拽实时调整?
解决方案
核心原因
- 音量赋值逻辑仅在播放触发时执行一次,滑块滑动过程中没有同步更新
AVAudioPlayer的volume属性 - 原有播放、停止方法每次执行都重复初始化播放器实例,属于冗余逻辑,也会干扰音量实时生效
修改方案
- 给
Slider添加数值变化监听回调,每次滑块值变动时直接更新正在运行的播放器音量 - 优化播放器初始化逻辑,避免每次播放/停止重复创建实例
修改后的完整代码如下:
import SwiftUI import AVFoundation var campFirePlayer: AVAudioPlayer! var campFireIsTapped: Bool = false struct CF_RowView: View { @State var SFname: String @State var nameOfSound: String @State var urlOfSound: String @State var slidervalue: Float var body: some View { HStack { Image(systemName: SFname) .frame(width: 20) // 音效开关按钮 Button(action: { campFireIsTapped.toggle() campFireIsTapped ? self.playCampFire() : self.stopCampFire() }) { Text(nameOfSound).frame(width: 150, alignment: .leading) } .padding(.leading, 10) .foregroundColor(Color.primary) Spacer() // 新增onChange监听滑块数值变化,实时更新音量 Slider(value: $slidervalue) .frame(width: 130, alignment: .trailing) .onChange(of: slidervalue) { newValue in guard campFirePlayer != nil, campFireIsTapped else { return } campFirePlayer.volume = newValue } }.frame(width:320) } // 优化后的播放音效方法,避免重复初始化 func playCampFire() { // 播放器仅初始化一次 if campFirePlayer == nil { let url = Bundle.main.url(forResource: urlOfSound, withExtension: "aif") guard let soundUrl = url else { return } do { campFirePlayer = try AVAudioPlayer(contentsOf: soundUrl) campFirePlayer.numberOfLoops = -1 } catch { print("播放器初始化失败:\(error)") return } } campFirePlayer.volume = slidervalue campFirePlayer.play() } // 优化后的停止音效方法 func stopCampFire() { guard campFirePlayer != nil else { return } campFirePlayer.stop() // 若需要下次播放从头开始可取消注释下方代码 // campFirePlayer.currentTime = 0 } }
兼容说明
如果需要适配iOS13及以下不支持onChange的系统版本,可以将滑块的Binding替换为自定义setter,或者使用Combine框架监听slidervalue的数值变化,实现逻辑一致。
内容的提问来源于stack exchange,提问作者Shannon Slater
相关产品推荐
相关产品推荐

