Swift4 修改循环播放逻辑实现交替切换音效的技术求助
实现交替播放两种音效的修改方案
嘿,我看了你的代码,要把单一音效重复播放改成交替播放两种音效(比如ababab)其实很容易,咱们来调整几个关键地方就行:
问题分析
你当前的代码只用了一个AVAudioPlayer实例,每次定时器触发都播放同一个音效,自然没法切换。咱们需要两个播放器实例分别对应两种音效,再加上一个变量来跟踪当前该播放哪一个,就能实现交替效果了。
修改步骤&完整代码
下面是修改后的代码,我标注了关键改动的地方:
import UIKit import AVFoundation class ViewController: UIViewController { @IBOutlet weak var whiste: UIImageView! @IBOutlet weak var textField: UITextField! // 播放次数输入框 @IBOutlet weak var textfield2: UITextField! // 间隔时长输入框 // 用数组存储两个音效的播放器(代替原来的单个player) var soundPlayers: [AVAudioPlayer] = [] var timer = Timer() var count: Int = 0 // 新增:跟踪当前要播放的音效索引(0或1,对应两种音效) var currentSoundIndex = 0 override func viewDidLoad() { super.viewDidLoad() // 提前加载两个音效,避免点击按钮时才加载导致延迟 loadSoundFiles() } // 加载两个音效文件到播放器数组 func loadSoundFiles() { // 第一个音效:regularWHistle.wav if let soundPath1 = Bundle.main.path(forResource: "regularWHistle", ofType: "wav"), let soundURL1 = URL(fileURLWithPath: soundPath1) { do { let player1 = try AVAudioPlayer(contentsOf: soundURL1) player1.prepareToPlay() // 预加载,提升播放流畅度 soundPlayers.append(player1) } catch { print("加载第一个音效失败:\(error.localizedDescription)") } } // 第二个音效:这里假设你的第二个音效叫"anotherWhistle.wav",记得替换成你实际的文件名 if let soundPath2 = Bundle.main.path(forResource: "anotherWhistle", ofType: "wav"), let soundURL2 = URL(fileURLWithPath: soundPath2) { do { let player2 = try AVAudioPlayer(contentsOf: soundURL2) player2.prepareToPlay() soundPlayers.append(player2) } catch { print("加载第二个音效失败:\(error.localizedDescription)") } } } @IBAction func playButtonTapped(_ sender: Any) { // 先检查两个音效是否都加载成功 guard soundPlayers.count == 2 else { let alert = UIAlertController(title: "错误", message: "音效文件加载失败,请检查文件名是否正确", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .cancel)) present(alert, animated: true) return } // 验证播放次数输入 guard let textValue = textField.text, let repeatCount = Int(textValue), repeatCount > 0 else { let alert = UIAlertController(title: "提示", message: "请输入有效的播放次数(大于0的整数)", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .cancel)) present(alert, animated: true) return } // 开始播放逻辑 playWith(repeatCount: repeatCount) } func playWith(repeatCount: Int) { // 先停止之前的定时器和播放,避免重复触发 timer.invalidate() count = 0 currentSoundIndex = 0 // 重置为第一个音效开始 // 获取间隔时长,默认0.36秒 var timeInterval = 0.36 if let textValue = textfield2.text, let inputInterval = Double(textValue), inputInterval > 0 { timeInterval = inputInterval } // 先播放第一个音效 soundPlayers[currentSoundIndex].play() currentSoundIndex = 1 - currentSoundIndex // 切换到下一个音效 // 启动定时器 timer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: true) { [weak self] timer in guard let self = self else { return } self.count += 1 if self.count < repeatCount { // 播放当前索引的音效,然后切换索引实现交替 self.soundPlayers[self.currentSoundIndex].play() self.currentSoundIndex = 1 - self.currentSoundIndex } else { // 播放次数达标,停止所有播放和定时器 self.soundPlayers.forEach { $0.stop() } timer.invalidate() self.count = 0 } } } }
关键改动说明
- 新增
loadSoundFiles方法:在viewDidLoad时提前加载两个音效,避免点击按钮时的延迟,同时用prepareToPlay预加载提升播放流畅度。 - 用数组存储两个播放器:
soundPlayers数组分别存两种音效的播放器,代替原来的单个player变量。 currentSoundIndex变量:用来跟踪当前要播放的音效索引,每次播放后切换成1 - currentSoundIndex(0变1,1变0),实现交替效果。- 完善输入验证:新增了音效加载失败的提示,确保两个音效都准备好才开始播放;同时保留了原有的输入合法性校验。
- 避免重复触发:每次点击播放按钮时先停止之前的定时器和播放,防止多个定时器同时运行导致混乱。
记得把代码里的anotherWhistle.wav替换成你实际的第二个音效文件名哦~
内容的提问来源于stack exchange,提问作者user8105388
相关产品推荐
相关产品推荐

