How to change volume programmatically on iOS 11.4
Changing volumeViewSlider.value
after a small delay resolves problem.
- (IBAction)increase:(id)sender {
MPVolumeView *volumeView = [[MPVolumeView alloc] init];
UISlider *volumeViewSlider = nil;
for (UIView *view in volumeView.subviews) {
if ([view isKindOfClass:[UISlider class]]) {
volumeViewSlider = (UISlider *)view;
break;
}
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
volumeViewSlider.value = 0.5f;
});
}
Swift version
I solved it by adding new MPVolumeView to my UIViewController view, otherwise it didn't set the volume anymore. As I added it to the controller I also need to set the volume view position to be outside of the screen to hide it from the user.
I prefer not to use delayed volume setting as it make things more complicated especially if you need to play sound immediately after setting the volume.
The code is in Swift 4:
let volumeControl = MPVolumeView(frame: CGRect(x: 0, y: 0, width: 120, height: 120))
override func viewDidLoad() {
self.view.addSubview(volumeControl);
}
override func viewDidLayoutSubviews() {
volumeControl.frame = CGRect(x: -120, y: -120, width: 100, height: 100);
}
func setVolume(_ volume: Float) {
let lst = volumeControl.subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}
let slider = lst.first as? UISlider
slider?.setValue(volume, animated: false)
}
I just added the MPVolumeView
as a subview to another view (that was never drawn on screen).
This had to be done prior to any attempt to set or get the volume.
private let containerView = UIView()
private let volumeView = MPVolumeView()
func prepareWorkaround() {
self.containerView.addSubview(self.volumeView)
}