How to change volume programmatically on iOS 11.4

2019-02-21 18:04发布

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.

4条回答
欢心
2楼-- · 2019-02-21 18:38

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)
}
查看更多
爱情/是我丢掉的垃圾
3楼-- · 2019-02-21 18:42

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)
}
查看更多
我想做一个坏孩纸
4楼-- · 2019-02-21 18:48

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

查看更多
Ridiculous、
5楼-- · 2019-02-21 18:51

I had to have a MPVolumeView as subview to a view in the hierarchy for the hud not to show up on iOS 12. It needs to be slightly visible:

let volume = MPVolumeView(frame: .zero)
volume.setVolumeThumbImage(UIImage(), for: UIControl.State())
volume.isUserInteractionEnabled = false
volumelume.alpha = 0.0001
volume.showsRouteButton = false
view.addSubview(volume)

When setting the volume I get the slider from MPVolumeView as with previous posters and set the value:

func setVolumeLevel(_ volumeLevel: Float) {
    guard let slider = volume.subviews.compactMap({ $0 as? UISlider }).first else {
        return
    }

    slider.value = volumeLevel
}
查看更多
登录 后发表回答