Swift中用UISlider+MPVolumeView调音量遇[MediaRemote]错误求助
自定义UISlider调节YouTube视频音量问题排查
我在ViewController中尝试用自定义UISlider调节YouTube视频的音量,采用MPVolumeView方案后,调试区出现[MediaRemote] No local output device available错误,以下是我的代码,求找出问题:
lazy var soundSlider: UISlider = { let slider = UISlider() slider.minimumTrackTintColor = .white slider.maximumTrackTintColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.7) slider.setThumbImage(UIImage(named: "Round_Thumb_VolumeBar"), for: .normal) slider.translatesAutoresizingMaskIntoConstraints = false slider.addTarget(self, action: #selector(handleVolumeSliderChange), for: .valueChanged) return slider }() @objc func handleVolumeSliderChange() { print(soundSlider.value) MPVolumeView.setVolume(soundSlider.value) } override func viewDidLoad() { super.viewDidLoad() view.addSubview(soundSlider) soundSlider.leadingAnchor.constraint(equalTo: soundMinButton.trailingAnchor, constant: 10).isActive = true soundSlider.trailingAnchor.constraint(equalTo: soundMaxButton.leadingAnchor, constant: -10).isActive = true soundSlider.topAnchor.constraint(equalTo: pausePlayButton.bottomAnchor, constant: 43).isActive = true } extension MPVolumeView { static func setVolume(_ volume: Float) { let volumeView = MPVolumeView() let volumeSlider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.01) { volumeSlider?.value = volume } } }
问题原因及修复方案
1. MPVolumeView使用错误
你在静态方法中每次创建新的MPVolumeView实例,但从未将其添加到视图层级。MPVolumeView需要被添加到视图(即使隐藏)才能让系统正确识别音频输出设备,否则会抛出设备不可用的错误。
修复代码:
// 在ViewController中添加全局MPVolumeView实例 private let volumeView = MPVolumeView() lazy var soundSlider: UISlider = { let slider = UISlider() slider.minimumTrackTintColor = .white slider.maximumTrackTintColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 0.7) slider.setThumbImage(UIImage(named: "Round_Thumb_VolumeBar"), for: .normal) slider.translatesAutoresizingMaskIntoConstraints = false slider.addTarget(self, action: #selector(handleVolumeSliderChange), for: .valueChanged) return slider }() @objc func handleVolumeSliderChange() { print(soundSlider.value) // 使用已初始化的volumeView实例获取滑块 if let systemVolumeSlider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider { systemVolumeSlider.value = soundSlider.value } } override func viewDidLoad() { super.viewDidLoad() // 将MPVolumeView添加到视图并隐藏 volumeView.isHidden = true view.addSubview(volumeView) view.addSubview(soundSlider) // 原有约束代码不变 soundSlider.leadingAnchor.constraint(equalTo: soundMinButton.trailingAnchor, constant: 10).isActive = true soundSlider.trailingAnchor.constraint(equalTo: soundMaxButton.leadingAnchor, constant: -10).isActive = true soundSlider.topAnchor.constraint(equalTo: pausePlayButton.bottomAnchor, constant: 43).isActive = true } // 移除原有的MPVolumeView扩展
2. 优先使用YouTube播放器原生API
如果你使用的是官方YTPlayerView,直接调节系统音量并非最优解,应该调用播放器自身的音量控制方法,这样更贴合YouTube视频的播放逻辑:
// 假设你有YTPlayerView实例 @IBOutlet weak var youtubePlayer: YTPlayerView! @objc func handleVolumeSliderChange() { // 将UISlider的0-1值转为YTPlayer的0-100音量范围 let targetVolume = Int(soundSlider.value * 100) youtubePlayer.setVolume(targetVolume) }
3. 额外注意点
- 模拟器可能会出现设备检测错误,建议用真机测试。
- iOS 13+系统中,直接修改系统音量可能受系统限制,若需调节系统音量,也可考虑使用
AVAudioSession的相关API,但需注意权限配置。
内容的提问来源于stack exchange,提问作者iOS Swift-man Junior
相关产品推荐
相关产品推荐

