如何让UIButton记住选中状态?儿童拼图App音乐按钮状态异常问题
问题描述
我正在开发一款面向儿童的拼图App,包含24个不同场景的小拼图。我通过单例类MusicHelper管理背景音乐,代码如下:
class MusicHelper { static let sharedHelper = MusicHelper() var audioPlayerBGM: AVAudioPlayer? func playBackgroundMusic() { let BGM = URL(fileURLWithPath: Bundle.main.path(forResource: "jigsawBGM", ofType: "wav")!) do { audioPlayerBGM = try AVAudioPlayer(contentsOf:BGM as URL) audioPlayerBGM!.numberOfLoops = -1 audioPlayerBGM!.prepareToPlay() audioPlayerBGM!.play() audioPlayerBGM!.volume = 0.1 } catch { print("Cannot play the file") } } func pauseBackgroundMusic() { let BGM = URL(fileURLWithPath: Bundle.main.path(forResource: "jigsawBGM", ofType: "wav")!) do { audioPlayerBGM = try AVAudioPlayer(contentsOf:BGM as URL) audioPlayerBGM!.pause() } catch { print("Cannot play the file") } } }
为了避免打扰家长,我写了一段代码实现背景音乐静音功能:
@IBOutlet weak var muteMusicButton: UIButton! @IBAction func muteMusic(_ sender: UIButton) { sender.isSelected = !sender.isSelected if muteMusicButton.isSelected { MusicHelper.sharedHelper.pauseBackgroundMusic() } else { MusicHelper.sharedHelper.playBackgroundMusic() } }
静音按钮muteMusicButton位于单独的视图控制器(类似应用的控制/设置窗口),是自定义按钮:默认状态显示“音乐开启”图片,选中状态显示“音乐关闭”图片。
问题:当该视图控制器被dismiss后,按钮会重置为默认状态。再次进入时,音乐仍处于暂停状态,但按钮显示“音乐开启”图片,需要点击两次才能重新播放音乐。
请问如何让按钮在视图控制器关闭/重新进入时记住选中状态?(可能用到UserDefaults,但我不太熟悉!)或者是否有其他不同的实现方式?
解决方案
首先要修复MusicHelper里的核心问题:你的pauseBackgroundMusic()方法每次都会重新创建新的AVAudioPlayer实例,而非暂停正在播放的那个,这会直接导致状态混乱,先修改这个基础问题:
class MusicHelper { static let sharedHelper = MusicHelper() var audioPlayerBGM: AVAudioPlayer? // 初始化时一次性加载音频资源,避免重复创建实例 init() { guard let path = Bundle.main.path(forResource: "jigsawBGM", ofType: "wav") else { print("BGM文件未找到") return } let bgmURL = URL(fileURLWithPath: path) do { audioPlayerBGM = try AVAudioPlayer(contentsOf: bgmURL) audioPlayerBGM?.numberOfLoops = -1 audioPlayerBGM?.volume = 0.1 audioPlayerBGM?.prepareToPlay() } catch { print("初始化BGM播放器失败:\(error)") } } func playBackgroundMusic() { audioPlayerBGM?.play() } func pauseBackgroundMusic() { audioPlayerBGM?.pause() } // 新增方法:判断当前音乐是否处于播放状态 func isMusicPlaying() -> Bool { return audioPlayerBGM?.isPlaying ?? false } }
接下来用UserDefaults保存静音状态,同时在视图控制器加载时同步按钮状态:
步骤1:定义UserDefaults的键(统一管理避免拼写错误)
可以在视图控制器内部或者全局常量文件中定义:
private let kMusicMutedKey = "MusicMutedStatus"
步骤2:修改按钮点击事件,同步保存状态
@IBAction func muteMusic(_ sender: UIButton) { sender.isSelected = !sender.isSelected // 将状态保存到UserDefaults UserDefaults.standard.set(sender.isSelected, forKey: kMusicMutedKey) if sender.isSelected { MusicHelper.sharedHelper.pauseBackgroundMusic() } else { MusicHelper.sharedHelper.playBackgroundMusic() } }
步骤3:在视图控制器显示时同步按钮状态
每次进入设置页面时,从UserDefaults读取保存的状态并设置按钮:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 读取保存的状态,默认值为false(即未静音、音乐开启) let isMuted = UserDefaults.standard.bool(forKey: kMusicMutedKey) muteMusicButton.isSelected = isMuted }
额外优化:App启动时自动恢复音乐状态
在SceneDelegate的启动方法中,根据保存的状态自动恢复音乐播放状态:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { let isMuted = UserDefaults.standard.bool(forKey: kMusicMutedKey) if !isMuted { MusicHelper.sharedHelper.playBackgroundMusic() } }
这样处理后,无论关闭再重新进入设置页面,按钮都会正确匹配当前的音乐状态,不会出现需要点击两次才能播放的问题。
内容的提问来源于stack exchange,提问作者KrisP
相关产品推荐
相关产品推荐

