繁体   English   中英

检测音量按钮按下

[英]Detect volume button press

未调用音量按钮通知功能。

代码:

func listenVolumeButton(){
    // Option #1
    NSNotificationCenter.defaultCenter().addObserver(self, selector: "volumeChanged:", name: "AVSystemController_SystemVolumeDidChangeNotification", object: nil)
    // Option #2
    var audioSession = AVAudioSession()
    audioSession.setActive(true, error: nil)
    audioSession.addObserver(self, forKeyPath: "volumeChanged", options: NSKeyValueObservingOptions.New, context: nil)
}

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
    if keyPath == "volumeChanged"{
        print("got in here")
    }
}

func volumeChanged(notification: NSNotification){
   print("got in here")
}

在 viewWillAppear 中调用listenVolumeButton()

在任何一种情况下,代码都没有到达打印语句"got in here"

我正在尝试两种不同的方法来做到这一点,这两种方法都不起作用。

我遵循了这个: 检测 iPhone 音量按钮向上按下?

使用第二种方法,键路径的值应该是"outputVolume" 这就是我们正在观察的属性。 所以把代码改成,

var outputVolumeObserve: NSKeyValueObservation?
let audioSession = AVAudioSession.sharedInstance()

func listenVolumeButton() {
    do {
        try audioSession.setActive(true)
    } catch {}

    outputVolumeObserve = audioSession.observe(\.outputVolume) { (audioSession, changes) in
        /// TODOs
    }
}

上面的代码在 Swift 3 中不起作用,在这种情况下,试试这个:

func listenVolumeButton() {
   do {
    try audioSession.setActive(true)
   } catch {
    print("some error")
   }
   audioSession.addObserver(self, forKeyPath: "outputVolume", options: NSKeyValueObservingOptions.new, context: nil)
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
  if keyPath == "outputVolume" {
    print("got in here")
  }
}

使用此代码,您可以在用户点击音量硬件按钮时收听。

class VolumeListener {
    static let kVolumeKey = "volume"

    static let shared = VolumeListener()

    private let kAudioVolumeChangeReasonNotificationParameter = "AVSystemController_AudioVolumeChangeReasonNotificationParameter"
    private let kAudioVolumeNotificationParameter = "AVSystemController_AudioVolumeNotificationParameter"
    private let kExplicitVolumeChange = "ExplicitVolumeChange"
    private let kSystemVolumeDidChangeNotificationName = NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification")

    private var hasSetup = false

    func start() {
        guard !self.hasSetup else {
            return
        }

        self.setup()
        self.hasSetup = true

    }

    private func setup() {
        guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else {
            return
        }

        let volumeView = MPVolumeView(frame: CGRect.zero)
        volumeView.clipsToBounds = true
        rootViewController.view.addSubview(volumeView)

        NotificationCenter.default.addObserver(
            self,
            selector: #selector(self.volumeChanged),
            name: kSystemVolumeDidChangeNotificationName,
            object: nil
        )

        volumeView.removeFromSuperview()
    }

    @objc func volumeChanged(_ notification: NSNotification) {
        guard let userInfo = notification.userInfo,
            let volume = userInfo[kAudioVolumeNotificationParameter] as? Float,
            let changeReason = userInfo[kAudioVolumeChangeReasonNotificationParameter] as? String,
            changeReason == kExplicitVolumeChange
            else {
                return
        }

        NotificationCenter.default.post(name: "volumeListenerUserDidInteractWithVolume", object: nil,
                                        userInfo: [VolumeListener.kVolumeKey: volume])
    }
}

要听,您只需要添加观察者:

NotificationCenter.default.addObserver(self, selector: #selector(self.userInteractedWithVolume),
                                           name: "volumeListenerUserDidInteractWithVolume", object: nil)

您可以通过检查 userInfo 来访问音量值:

@objc private func userInteractedWithVolume(_ notification: Notification) {
    guard let volume = notification.userInfo?[VolumeListener.kVolumeKey] as? Float else {
        return
    }

    print("volume: \(volume)")
}
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
  } 
}

在观察新值时,我将系统音量设置回 0.5。 这可能会激怒同时使用音乐的用户,因此我不建议在制作中使用我自己的答案。

如果有兴趣,这里有一个 RxSwift 版本。

func volumeRx() -> Observable<Void> {
    Observable<Void>.create {
        subscriber in
        
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setActive(true)
        } catch let e {
            subscriber.onError(e)
        }

        let outputVolumeObserve = audioSession.observe(\.outputVolume) {
            (audioSession, changes) in
            subscriber.onNext(Void())
        }
        
        return Disposables.create {
            outputVolumeObserve.invalidate()
        }
    }
}

用法

volumeRx()
   .subscribe(onNext: {
      print("Volume changed")
   }).disposed(by: disposeBag)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM