Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change volume programmatically on iOS 11.4

Before, I was setting sound volume programmatically using this approach:

MPVolumeView *volumeView = [[MPVolumeView alloc] init];
UISlider *volumeViewSlider = nil;

for (UIView *view in [volumeView subviews])
{
    if ([view.class.description isEqualToString:@"MPVolumeSlider"])
    {
        volumeViewSlider = (UISlider *)view;
        break;
    }
}

[volumeViewSlider setValue:0.5 animated:YES];
[volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];

Till iOS 11.4 it was working well (even on iOS 11.3), but on iOS 11.4 it doesn't. Volume value remains unchanged. Can someone help with this issue? Thanks.

like image 697
iOS Dev Avatar asked Jun 07 '18 09:06

iOS Dev


3 Answers

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)
}
like image 168
Northern Captain Avatar answered Nov 14 '22 04:11

Northern Captain


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

like image 40
trungduc Avatar answered Nov 14 '22 04:11

trungduc


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)
}
like image 1
Ric Santos Avatar answered Nov 14 '22 06:11

Ric Santos