【问题标题】:Detect iPhone Volume Button Up Press?检测 iPhone 音量按钮向上按下?
【发布时间】:2012-03-28 11:04:37
【问题描述】:

当 iPhone 的音量调高时,我是否可以听到通知?

我知道AVSystemController_SystemVolumeDidChangeNotification,但重要的是只有在音量调高而不是调高或调低时才会触发通知。

其次,如何隐藏按下音量增大按钮时出现的半透明视图,显示系统音量? Camera+ 已实现此功能。

【问题讨论】:

    标签: iphone objective-c ios volume avsystemcontroller


    【解决方案1】:

    没有记录的方法可以解决此问题,但您可以使用此解决方法。注册AVSystemController_SystemVolumeDidChangeNotification 通知并添加MPVolumeView,这将阻止系统卷视图显示。

    MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, 0, 10, 0)];
    [volumeView sizeToFit];
    [self.view addSubview:volumeView];
    

    别忘了启动音频会话

    AudioSessionInitialize(NULL, NULL, NULL, NULL);
    AudioSessionSetActive(true);
    

    在这种情况下,MPVolumeView 对用户隐藏。

    至于检查是否按下了音量增大或减小,只需抓住当前应用程序的音量即可

    float volumeLevel = [[MPMusicPlayerController applicationMusicPlayer] volume];  
    

    并在通知回调中按下按钮后将其与新音量进行比较

    如果你不想自己做,github上有一个drop-in class可用

    https://github.com/blladnar/RBVolumeButtons

    【讨论】:

    • 我注意到使用此方法的一件事是,如果我有另一个应用程序在后台播放音乐(或者如果您已经在执行此检测的应用程序中播放音乐),我将停止接收通知,并且音量按钮将恢复为仅更改在后台播放的音乐的音量 =/
    • [[MPMusicPlayerController applicationMusicPlayer] volume] 自 iOS 7 起已被弃用。
    【解决方案2】:

    如果你想要一个事件,你可以在“outputVolume”属性上注册一个监听器:

    - (void)viewWillAppear:(BOOL)animated {
    
        AVAudioSession* audioSession = [AVAudioSession sharedInstance];
    
        [audioSession setActive:YES error:nil];
        [audioSession addObserver:self
                        forKeyPath:@"outputVolume"
                           options:0
                           context:nil];
    }
    
    -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    
        if ([keyPath isEqual:@"outputVolume"]) {
            NSLog(@"volume changed!");
        }
    }
    

    【讨论】:

    • 我在 stackoverflow 上看过这么多地方,这是唯一一个使用非弃用方法和字符串来完成这项工作的地方。
    • 这个解决方案的问题是,如果 outputVolume 已经是 max 并且他们按下 + 按钮,回调就不会发生。
    • 这个解决方案非常好,但是 ray 是对的 :( 是否可以通过编程将值重置为 0?
    • 当音量最大时,我如何才能调用该操作?
    • @AustinT @donmarkusi 您可以尝试读取当前音量,如果它处于最大值,则将其设置回 (max - 1)。查看UISlidersetValue:animated: 将其设置为UIControlEventTouchUpInside
    【解决方案3】:

    我通过为放置在MPVolumeView 中的 UISlider 添加自己的目标/动作来解决了这个问题。因此可以捕获音量变化事件并确定按下了哪个按钮。这是github repo,实现了这种方法。 它适用于 iOS 7 及更高版本,没有弃用警告,也没有被 Apple 拒绝。

    【讨论】:

      【解决方案4】:

      为了区分音量动作:INSTEAD OF(在observeValue中)

      temp != 0.5
      

      使用只提高音量

      temp > 0.5
      

      并且只检测音量降低:

      temp < 0.5 
      

      如果按下音量增大或减小,则下面的此解决方案将打印出来。

      import AVFoundation
      import MediaPlayer
      
      override func viewDidLoad() {
        super.viewDidLoad()
        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?.sendSubview(toBack: volumeView)
      }
      
      override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        AVAudioSession.sharedInstance().addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
        do { try AVAudioSession.sharedInstance().setActive(true) }
        catch { debugPrint("\(error)") }   
      }
      
      override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        AVAudioSession.sharedInstance().removeObserver(self, forKeyPath: "outputVolume")
        do { try AVAudioSession.sharedInstance().setActive(false) } 
        catch { debugPrint("\(error)") }
      }
      
      override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        guard let key = keyPath else { return }
        switch key {
          case "outputVolume":
            guard let dict = change, let temp = dict[NSKeyValueChangeKey.newKey] as? Float, temp != 0.5 else { return }
            let systemSlider = MPVolumeView().subviews.first { (aView) -> Bool in
              return NSStringFromClass(aView.classForCoder) == "MPVolumeSlider" ? true : false
            } as? UISlider
            systemSlider?.setValue(0.5, animated: false)
            guard systemSlider != nil else { return }
            debugPrint("Either volume button tapped.")
          default:
            break
        } 
      }
      

      【讨论】:

        猜你喜欢
        • 2015-04-12
        • 2011-11-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多