首页 > 解决方案 > AVFoundation 音频播放器仅在播放器停止时从滑块更新音量。我希望在拖动滑块时音量实时更新

问题描述

我正在构建的内容:一个应用程序,用户可以在其中以不同的音量播放不同的环境噪音。

问题:我希望在拖动滑块时音量自动改变。在其当前状态下,如果我停止播放器然后再次播放,它只会反映音量的变化。

问题示例:我点击一个声音来播放它(在这种情况下,是篝火的声音)。它开始正常播放。我将音量滑块拖动到不同的值以更改音量。这应该改变我听到的声音的音量,但音量没有变化。如果我点击声音将其关闭,然后再次点击将其重新打开,我只能听到新音量级别的声音。只有这样它才能反映新的音量水平。

我认为问题出在哪里:我相信问题出在函数 playCampFire() 内部。这是我在 do{} 语句中插入音量功能的地方。我认为是因为代码仅在执行 playCampFire() 函数时才执行,这仅在点击声音时发生。我尝试将 .volume 放在文件的不同部分,而不是仅仅将它放在 playCampFire() 函数中,但我没有运气。

这是我的代码:

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 to turn the sound on or off
            Button(action: {
                campFireIsTapped.toggle()
                campFireIsTapped ? self.playCampFire() : self.stopCampFire()
            }) {
                Text(nameOfSound).frame(width: 150, alignment: .leading)
            }
            .padding(.leading, 10)
            .foregroundColor(Color.primary)
            Spacer()
            Slider(value: $slidervalue)
                .frame(width: 130, alignment: .trailing)
        }.frame(width:320)
    }
    
    // function to play the sound
    func playCampFire() {
        let url = Bundle.main.url(forResource: urlOfSound, withExtension: "aif")
        
        guard url != nil else {
            return
        }
        
        do {
            campFirePlayer = try AVAudioPlayer(contentsOf: url!)
            campFirePlayer?.play()
            campFirePlayer?.numberOfLoops = -1
            campFirePlayer.volume = slidervalue
        } catch {
            print("\(error)")
        }
    }
    
    // function to turn off the sound
    func stopCampFire() {
        let url = Bundle.main.url(forResource: urlOfSound, withExtension: "aif")
        
        guard url != nil else {
            return
        }
        
        do {
            campFirePlayer = try AVAudioPlayer(contentsOf: url!)
            campFirePlayer?.stop()
        } catch {
            print("\(error)")
        }
    }
}

这是预览的屏幕截图...

预习

问题:我应该将 .volume 放在我的代码中的哪个位置,以便在我拖动音量滑块时它会自动更新,而无需停止声音并再次播放?

标签: swiftxcodeswiftuiavfoundation

解决方案


我建议使用onChange来检测值何时更新。只需更新您的代码即可:

var body: some View {
        HStack {
            Image(systemName: SFname)
                .frame(width: 20)
            

            // Button to turn the sound on or off
            Button(action: {
                campFireIsTapped.toggle()
                campFireIsTapped ? self.playCampFire() : self.stopCampFire()
            }) {
                Text(nameOfSound).frame(width: 150, alignment: .leading)
            }
            .padding(.leading, 10)
            .foregroundColor(Color.primary)
            Spacer()
            Slider(value: $slidervalue)
                .frame(width: 130, alignment: .trailing)
        }
        .frame(width:320)
        .onChange(of: self.slidervalue) { value in
            self.campFirePlayer.volume = value
        }
    }

推荐阅读