【问题标题】:How to change device Volume on iOS - not music volume如何在 iOS 上更改设备音量 - 而不是音乐音量
【发布时间】:2012-05-04 10:20:02
【问题描述】:

我想在 iOS (iphone) 上更改设备音量。

我知道我可以用下面这行来改变音乐库的音量:

//implement at first MediaPlayer framework
MPMusicPlayerController *musicPlayer = [MPMusicPlayerController iPodMusicPlayer];
musicPlayer.volume = 1;

但这不是我的目标。
我想改变设备音量或让我说铃声的音量。

我该怎么做?只需更改 DEVICE 音量?

【问题讨论】:

    标签: ios iphone device volume


    【解决方案1】:

    您必须使用 applicationMusicPlayer 而不是 iPodMusicPlayer 来设置系统音量:

    #import <MediaPlayer/MediaPlayer.h>
    musicPlayer = [MPMusicPlayerController applicationMusicPlayer];
    musicPlayer.volume = 1; // max volume
    musicPlayer.volume = 0; // min volume (mute)
    musicPlayer.volume = 0.0625; // 1 bar on the overlay volume display
    

    【讨论】:

    • 注意:这在 iOS 7 中已被弃用
    【解决方案2】:

    回答brush51的问题:

    我该怎么做?只需更改 DEVICE 音量?

    正如 0x7fffffff 建议的那样:

    您无法以编程方式更改设备音量,但 MPVolumeView(音量滑块)可用于更改设备音量,但只能通过用户交互。

    所以,Apple 推荐使用MPVolumeView,所以我想出了这个:

    添加volumeSlider属性:

    @property (nonatomic, strong) UISlider *volumeSlider;
    

    初始化 MPVolumeView 并在视图中添加某个位置(可以隐藏,没有框架,或者因为 showsRouteButton = NOshowsVolumeSlider = NO 而为空):

    MPVolumeView *volumeView = [MPVolumeView new];
    volumeView.showsRouteButton = NO;
    volumeView.showsVolumeSlider = NO;
    [self.view addSubview:volumeView];
    

    查找并保存对UISlider的引用:

    __weak __typeof(self)weakSelf = self;
    [[volumeView subviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        if ([obj isKindOfClass:[UISlider class]]) {
            __strong __typeof(weakSelf)strongSelf = weakSelf;
            strongSelf.volumeSlider = obj;
            *stop = YES;
        }
    }];
    

    UIControlEventValueChanged 添加目标操作:

    [self.volumeSlider addTarget:self action:@selector(handleVolumeChanged:) forControlEvents:UIControlEventValueChanged];
    

    然后检测音量变化(即通过硬件音量控制):

    - (void)handleVolumeChanged:(id)sender
    {
        NSLog(@"%s - %f", __PRETTY_FUNCTION__, self.volumeSlider.value);
    }
    

    还有其他方式,您可以通过以下方式设置音量:

    self.volumeSlider.value = < some value between 0.0f and 1.0f >;
    

    希望这会有所帮助(并且 Apple 不会从 MPVolumeView 中删除 MPVolumeSlider)。

    【讨论】:

    • 你测试过吗?您是否因以编程方式更改音量而被拒绝?
    • 在 ios 7.1 和 8 上对我不起作用。滑块的值会发生变化,但系统音量不会。
    • @msrdjan:当我签入 ios 8.3 时,如果 volumeView.showsRouteButton = NO; volumeView.showsVolumeSlider = NO; 应保持默认为 YES,则不会设置音量值
    • 在我的测试中,这只在同时连续播放声音并且首先将音量设置为大于 0 然后降低到 0 时才有效 - 仅供遇到相同问题的人参考跨度>
    【解决方案3】:

    这是我所做的:

    func setSystemVolume(volume: Float) {
        let volumeView = MPVolumeView()
    
        for view in volumeView.subviews {
            if (NSStringFromClass(view.classForCoder) == "MPVolumeSlider") {
                let slider = view as! UISlider
                slider.setValue(volume, animated: false)
            }
        }
    }
    

    由于 MPMusicPlayerController 中的属性 volume 在 iOS 7 中已弃用。这是您唯一可以做到的方法。

    【讨论】:

    • 我很好奇,虽然这有效,但它是否通过了 App Store 审核?
    【解决方案4】:

    这是一个小包装类,可以设置系统音量并通知您任何更改(将您自己的更改响应程序传递给 setTarget:action:)。

    编辑:如果您隐藏 MPVolumeView 控件或不将其添加为子视图,那么每当您以编程方式更改音量时,系统都会在屏幕中间显示默认音量方块。如果您不喜欢系统所做的事情,解决方案是在屏幕外设置视图坐标。我在下面编辑了我的代码以反映这一点。

    @import MediaPlayer;
    
    
    @interface SysVolumeControl : MPVolumeView
    @property (nonatomic) float value; // from 0 to 1.0
    - (void)setTarget:(id)target action:(SEL)action;
    @end
    
    
    @implementation SysVolumeControl
    {
        UISlider* _slider;
    }
    
    - (id)init
    {
        if (self = [super initWithFrame:CGRectMake(-300, 0, 200, 50)])
        {
            for (UIView* view in self.subviews)
            {
                if ([view isKindOfClass:UISlider.class])
                {
                    _slider = (UISlider*)view;
                    break;
                }
            }
        }
        return self;
    }
    
    - (float)value
        { return _slider.value; }
    
    - (void)setValue:(float)value
        { _slider.value = value; }
    
    - (void)setTarget:(id)target action:(SEL)action
        { [_slider addTarget:target action:action forControlEvents:UIControlEventValueChanged]; }
    
    @end
    

    然后创建一个实例并使用它:

    SysVolumeControl* sysVolumeControl = [SysVolumeControl new];
    [myView addSubview:sysVolumeControl];
    sysVolumeControl.value = 1.0;
    [sysVolumeControl setTarget:self action:@selector(mySysVolumeResponder:)];
    

    【讨论】:

      【解决方案5】:

      这个 (Swift) 解决方案对我来说非常有用: http://weimenglee.blogspot.com/2015/07/ios-tip-programmatically-adjust-device.html

      import MediaPlayer
      
      let volumeView = MPVolumeView()
      if let view = volumeView.subviews.first as? UISlider{
          view.value = 0.1 //---0 t0 1.0---
      
      }
      

      【讨论】:

      • 感谢您的帮助 - 为我节省了几个小时或更长时间试图弄清楚如何干净地访问该滑块。我不得不说,这对苹果来说太愚蠢了——我的应用程序都是手势,滑块没有位置。希望他们不要以此为由拒绝。我会在代码中留下一个很好的注释。
      • 请注意:在应用程序外部(如控制中心)更改音量会导致此功能不再起作用。它可能是我使用它的地方,但我把它作为一个全局变量放在 appDelegate 中,它似乎可以工作。在许多情况下,我的起始值也为 0。 volumeView.setNeedsLayout() 在 get/set of values 修复该问题之前的某个时间点。
      【解决方案6】:

      Swift 3 - 我用这个:

      func setVolumeTo(volume: Float) {
        (MPVolumeView().subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}.first as? UISlider)?.setValue(volume, animated: false)
      }
      

      【讨论】:

      【解决方案7】:

      动态创建 MPVolumeView 以获取滑块并设置音量在 iOS 11.4 中不再起作用。 我通过将新的 MPVolumeView 添加到我的 UIViewController 视图解决了这个问题,否则它没有设置音量。当我将它添加到控制器时,我还需要将音量视图位置设置在屏幕之外。

      代码在 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 setMaxVolume() {
          let lst = volumeControl.subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}
          let slider = lst.first as? UISlider
      
          slider?.setValue(1, animated: false)
      }
      

      【讨论】:

      【解决方案8】:

      应用不应更改设备全局设置,您也不应这样做。用户可以使用标准 iOS 功能做到这一点。 相反,如果您播放声音/视频,请使用播放器的volume:

      var player: AVPlayer!
      ...
      player.volume = 0.5 // 50% level
      

      【讨论】:

        【解决方案9】:

        在您的viewDidLoad 中调用listenVolumeButton 并将// 行替换为您想做的任何事情。

        private func listenVolumeButton() {
            let audioSession = AVAudioSession.sharedInstance()
            try? audioSession.setActive(true)
            audioSession.addObserver(self,
                                     forKeyPath: "outputVolume",
                                     options: NSKeyValueObservingOptions.new,
                                     context: nil)
        
            hideVolumeView()
        }
        
        private func hideVolumeView() {
            let volumeView = MPVolumeView(frame: CGRect.zero)
            for subview in volumeView.subviews {
                if let button = subview as? UIButton {
                    button.setImage(nil, for: .normal)
                    button.isEnabled = false
                    button.sizeToFit()
                }
            }
            UIApplication.shared.windows.first?.addSubview(volumeView)
            UIApplication.shared.windows.first?.sendSubviewToBack(volumeView)
        }
        
        override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
            switch keyPath {
            case "outputVolume":
                guard let systemSlider = MPVolumeView().subviews.first(where: { NSStringFromClass($0.classForCoder) == "MPVolumeSlider" }) as? UISlider else {
                    return
                }
        
                let avoidLimitsValue = max(min(AVAudioSession.sharedInstance().outputVolume, Float(0.9)), Float(0.1))
        
                DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.01) {
                    systemSlider.setValue(avoidLimitsValue, animated: false)
                }
        
                // DO YOUR STUFF HERE
            default:
                break
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2016-01-09
          • 1970-01-01
          • 2013-10-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-08
          • 2018-10-23
          相关资源
          最近更新 更多