SwiftUI中的AVAudioPlayer延迟

编程语言 2026-07-11

我正在做一个非常简单的ABC应用,每个字母都有一个按钮。点击其中一个按钮,对应的mp3就会播放。这是按钮的代码:

struct KeyCell: View {

    @State private var player: AVAudioPlayer?

    let character: Character
    let color: Color
    let onTap: (Character) -> Void

    var body: some View {

        Button(action: keypressed) {
            Circle()
                .fill(color)
                .frame(width: 80, height: 80)
                .padding()
                .overlay {
                    Text(character.character)
                        .font(Font.system(size: 60))
                        .fontWeight(.medium)
                }
        }
        .buttonStyle(.plain)
    }

    private func keypressed() {
        onTap(character)
        guard let soundURL = Bundle.main.url(forResource: character.file, withExtension: "mp3") else {
          return
        }

        do {
          player = try AVAudioPlayer(contentsOf: soundURL)
        } catch {
          print("Failed to load the sound: \(error)")
        }
        player?.play()
    }
}

我发现一个问题:A按钮会立刻播放。B会有一点延迟,C的延迟更长,依此类推,直到Z 需要好几秒才播放完毕。

我尝试过的方法:

  • 将AVAudioPlayer的创建移到.task中:
@State private var player: AVAudioPlayer?
    .
    .
    .
Button(action: keypressed) {...}
.task {
    guard let soundURL = Bundle.main.url(forResource: character.file, withExtension: "mp3") else { return }
    player = try? AVAudioPlayer(contentsOf: soundURL)
}

private func keypressed() {
    player?.play()
}
  • 使用这个示例创建一个声音播放器类 示例:
class Sounds {

   static var audioPlayer:AVAudioPlayer?

   static func playSounds(soundfile: String) {

       if let path = Bundle.main.path(forResource: soundfile, ofType: "mp3") {

           do{

               audioPlayer = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: path))
               audioPlayer?.prepareToPlay()
               audioPlayer?.play()

           }catch {
               print("Error")
           }
       }
    }
 }

然后就像这样播放:

private func keypressed() {
   Sounds.playSounds(soundfile: character.file)
}

以上方法都没有解决问题。有什么建议吗?

解决方案

尝试使用一个单例(SoundManager)来管理字符声音的播放。

示例代码,请根据你的需求调整逻辑:

import SwiftUI
import AVFoundation


struct  ContentView: View {
    let characters = [
        Character(character: "A", file: "testA"),
        Character(character: "B", file: "testB"),
        Character(character: "C", file: "testC")
    ]
    let color: Color = Color.green

    var body: some View {
        ForEach(characters) { character in
            KeyCell(character: character, color: color)
        }
    }
}

struct KeyCell: View {
    let character: Character
    let color: Color

    var body: some View {
        Button {
            SoundManager.shared.togglePlay(character: character)
        } label: {
            Circle()
                .fill(color)
                .frame(width: 80, height: 80)
                .padding()
                .overlay {
                    Text(character.character)
                        .font(.system(size: 60, weight: .medium))
                }
        }
        .buttonStyle(.plain)
    }
}

struct Character: Identifiable {
    let id = UUID()
    var character: String
    var file: String
}

class SoundManager {
    static let shared = SoundManager()

    private var player: AVAudioPlayer?
    private var currentFile: String?

    func togglePlay(character: Character) {
        if player?.isPlaying == true {
            player?.stop()
            return  // <--- adjust
        }

        // Only re-create if needed
        if currentFile != character.file {
            guard let url = Bundle.main.url(forResource: character.file, withExtension: "mp3") else {
                return
            }
            do {
                player = try AVAudioPlayer(contentsOf: url)
                currentFile = character.file
            } catch {
                print("Error: \(error)")
                return
            }
        }

        player?.play()
    }
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章