在 iOS 8 上按下音量增/减按钮的最佳/最干净方法是什么?
理想情况下,我想要捕获按键并防止系统音量发生变化(或者至少阻止音量变化HUD显示)。
有一些旧答案会使用已弃用的方法,但在iOS 8上似乎根本不起作用。iOS 8 specific one也无效。
这个RBVolumeButtons开源类似乎也不适用于iOS 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的出色回应。