iOS 8上最清晰的捕获音量上/下按钮的方法

时间:2015-01-28 13:36:15

标签: ios ios8 volume

iOS 8 上按下音量增/减按钮的最佳/最干净方法是什么?

理想情况下,我想要捕获按键并防止系统音量发生变化(或者至少阻止音量变化HUD显示)。


有一些旧答案会使用已弃用的方法,但在iOS 8上似乎根本不起作用。iOS 8 specific one也无效。

这个RBVolumeButtons开源类似乎也不适用于iOS 8。

8 个答案:

答案 0 :(得分:11)

对于Swift,您可以在viewController类中使用下一个代码:

let volumeView = MPVolumeView(frame: CGRectMake(-CGFloat.max, 0.0, 0.0, 0.0))
self.view.addSubview(volumeView)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(volumeChanged(_:)), name: "AVSystemController_SystemVolumeDidChangeNotification", object: nil)

然后添加此功能

func volumeChanged(notification: NSNotification) {

     if let userInfo = notification.userInfo {
        if let volumeChangeType = userInfo["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String {
            if volumeChangeType == "ExplicitVolumeChange" {
                // your code goes here
            }
        }
    }
}

此代码检测用户的显式卷更改操作,就像您没有检查显式操作一样,此函数将定期自动调用。

此代码不会阻止系统卷更改

答案 1 :(得分:10)

首先添加 AVFoundation MediaPlayer 框架,然后您可以使用以下代码检测按下向上/向下按钮,

-(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"]) {        
      float volumeLevel = [[MPMusicPlayerController applicationMusicPlayer] volume];
      NSLog(@"volume changed! %f",volumeLevel);
  }
}

答案 2 :(得分:9)

对于swift 3: (记得添加:import MediaPlayer ..)

    override func viewDidLoad() {
        super.viewDidLoad()

        let volumeView = MPVolumeView(frame: CGRect(x: 0, y: 40, width: 300, height: 30))
        self.view.addSubview(volumeView)
//      volumeView.backgroundColor = UIColor.red
        NotificationCenter.default.addObserver(self, selector: #selector(volumeChanged(notification:)),
                                               name: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"),
                                               object: nil)
    }


    func volumeChanged(notification: NSNotification) {

        if let userInfo = notification.userInfo {
            if let volumeChangeType = userInfo["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String {
                if volumeChangeType == "ExplicitVolumeChange" {
                    // your code goes here
                }
            }
        }
    }

...

答案 3 :(得分:1)

好的,请参阅音频会话服务参考了解更多信息。您需要使用AudioSessionInitialize启动音频会话,然后使用AudioSessionSetActive使其处于活动状态,使用AudioSessionAddPropertyListener侦听音量的变化,并传递类型为AudioSessionPropertyListener的回调。

这个网站写得很好:http://fredandrandall.com/blog/2011/11/18/taking-control-of-the-volume-buttons-on-ios-like-camera/

答案 4 :(得分:1)

Objective-C版本(使用通知):

#import <MediaPlayer/MPVolumeView.h>
#import <AVFoundation/AVFoundation.h>

@interface ViewController () {
    UISlider *volumeViewSlider;
}

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self startTrackingVolumeChanges];
}

- (void)dealloc
{
    [self stopTrackingVolumeChanges];
}

#pragma mark - Start Tracking Volume Changes

- (void)startTrackingVolumeChanges
{
    [self setupVolumeViewSlider];
    [self addObserver];
    [self activateAudioSession];
}

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

- (void)addObserver
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
}

- (void)activateAudioSession
{
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayback withOptions:AVAudioSessionCategoryOptionMixWithOthers error:nil];
    NSError *error;
    BOOL success = [audioSession setActive:YES error:&error];
    if (!success) {
        NSLog(@"Error activating audiosession: %@", error);
    }
}

#pragma mark - Observing Volume Changes

- (void)volumeChanged:(NSNotification *)notification
{
    NSString *volumeChangeType = notification.userInfo[@"AVSystemController_AudioVolumeChangeReasonNotificationParameter"];
    if ([volumeChangeType isEqualToString:@"ExplicitVolumeChange"]) {
        float volume = volumeViewSlider.value;
        NSLog(@"volume = %f", volume);
    }
}

#pragma mark - Stop Tracking Volume Changes

- (void)stopTrackingVolumeChanges
{
    [self removeObserver];
    [self deactivateAudioSession];
    volumeViewSlider = nil;
}

- (void)removeObserver
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
}

- (void)deactivateAudioSession
{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSError *error;
        BOOL success = [[AVAudioSession sharedInstance] setActive:NO error:&error];
        if (!success) {
            NSLog(@"Error deactivating audiosession: %@", error);
        }
    });
}

@end

答案 5 :(得分:1)

Swift 5 / iOS 13

您已经需要一个MPVolumeView才能使系统隐藏音量更改HUD。我找到的最简单,最可靠的解决方案是观察MPVolumeView本身的变化。

在设置过程中,通常在viewDidLoad()中:

// Create offscreen MPVolumeView
let systemVolumeView = MPVolumeView(frame: CGRect(x: -CGFloat.greatestFiniteMagnitude, y: 0, width: 0, height: 0))
myContainerView.addSubview(systemVolumeView)
let systemVolumeSlider = systemVolumeView.subviews.first(where:{ $0 is UISlider }) as? UISlider

// Observe volume changes (including from hardware buttons):
systemVolumeSlider.addTarget(self, action: #selector(volumeDidChange), for: .valueChanged)

响应以更改音量:

@objc func volumeDidChange() {
    // Handle volume change
}

答案 6 :(得分:0)

这是一个分为两部分的答案,它们是独立的,在 Swift 5 中。

要监听音量触发事件,

import MediaPlayer

// Observe in eg. viewDidLoad
let volumeChangedSystemName = NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification")
NotificationCenter.default.addObserver(self, selector: #selector(volumeChanged), name: volumeChangedSystemName, object: nil)

@objc private func volumeChanged(notification: NSNotification) {
    guard
        let info = notification.userInfo, 
        let reason = info["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String,
        reason == "ExplicitVolumeChange" else { return }

    // Handle it
}

要隐藏系统音量控制,

// Add the view but not visible
let volumeView = MPVolumeView(frame: CGRect(x: -CGFloat.greatestFiniteMagnitude, y: 0, width: 0, height: 0))
view.addSubview(volumeView)

答案 7 :(得分:0)

组合解决方案(已通过Swift 5.2 / iOS 14测试)

  • 确保将必要的框架导入文件;
import Combine
import MediaPlayer
  • 在函数之外为您的合并AnyCancellable设置一个变量;

var volumeCancellable: AnyCancellable?

  • 在与您的需求相关的任何功能(viewDidLoad或其他地方)中,配置组合订户;
volumePublisher = NotificationCenter.default
   .publisher(for: NSNotification.Name(rawValue: "AVSystemController_SystemVolumeDidChangeNotification"))
   .compactMap { $0.userInfo!["AVSystemController_AudioVolumeChangeReasonNotificationParameter"] as? String }
   .filter { $0 == "ExplicitVolumeChange" }
   .sink(receiveValue: { (val) in
       // Do whatever you'd like here
   })
  • 在与您的需求相关的任何功能中(同样,viewDidLoad或其他地方),设置音量控制并在屏幕外定位;
let volumeView = MPVolumeView(frame: CGRect(x: -CGFloat.greatestFiniteMagnitude, y: 0, width: 0, height: 0))
view.addSubview(volumeView)

基于上述@samwize的出色回应。