iOS 9: How to change volume programmatically without showing system sound bar popup?
I have to change the volume on iPad and using this code:
[[MPMusicPlayerController applicationMusicPlayer] setVolume:0];
But this changing volume and showing system volume bar on iPad. How to change the sound without showing the volume bar?
I know, setVolume:
is deprecated, and everybody says to use MPVolumeView
. If this is the only way to solve my problem, then how to change the volume using MPVolumeView
? I don't see any method in MPVolumeView
that changes the sound.
Should I use some another class together with MPVolumeView
?
But it's preferable to use MPMusicPlayerController
.
Thank you for advice!
For 2018, working on iOS 11.4
You need to change slider.value
after a small delay.
extension MPVolumeView {
static func setVolume(_ volume: Float) {
let volumeView = MPVolumeView()
let slider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.01) {
slider?.value = volume
}
}
}
Usage:
MPVolumeView.setVolume(0.5)
Objective-C version
MPVolumeView
has a slider, and by changing the value of the slider, you can change the device volume. I wrote an MPVolumeView
extension to easily access the slider:
extension MPVolumeView {
var volumeSlider:UISlider {
self.showsRouteButton = false
self.showsVolumeSlider = false
self.hidden = true
var slider = UISlider()
for subview in self.subviews {
if subview.isKindOfClass(UISlider){
slider = subview as! UISlider
slider.continuous = false
(subview as! UISlider).value = AVAudioSession.sharedInstance().outputVolume
return slider
}
}
return slider
}
}
extension UIViewController {
func setVolumeStealthily(_ volume: Float) {
guard let view = viewIfLoaded else {
assertionFailure("The view must be loaded to set the volume with no UI")
return
}
let volumeView = MPVolumeView(frame: .zero)
guard let slider = volumeView.subviews.first(where: { $0 is UISlider }) as? UISlider else {
assertionFailure("Unable to find the slider")
return
}
volumeView.clipsToBounds = true
view.addSubview(volumeView)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { [weak slider, weak volumeView] in
slider?.setValue(volume, animated: false)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { [weak volumeView] in
volumeView?.removeFromSuperview()
}
}
}
}
Usage:
// set volume to 50%
viewController.setVolume(0.5)