iOS监听音量调节

iOS的AVFoundation框架提供了基本的音视频播放工具,我们基本上可以靠其中提供的类完成绝大部分的音视频播放任务。但是在音频播放的输出音量的处理上,苹果的策略比较保守。尽管AVPlayerAVPAudiolayerzhe这些类提供了音量调节功能,但这些音量控制属于App级别的控制。好处就是音量调节独立于系统音量,调节大小时不会影响系统音量。但有时候我们可能希望修改系统音量,以免在调节声音的时候,如果系统音量过小,App调节音量效果不明显。一般来说要调节系统音量会有以下方法:

请注意:修改系统音量无法在模拟器上看到效果,必须使用真机调试才能看到效果!

使用MPVolumeView

这个方法是苹果官方推荐的方法。MPVolumeView是Media Player Framework中的一个UI组件,直接包含了对系统音量和Airplay设备的音频镜像路由的控制功能。其中包含一个MPVolumeSlider的subview用来控制音量。这个MPVolumeSlider是一个私有类,我们无法手动创建此类,但这个类是UISlider的子类。MPVolumeView的使用很简单,只需要将其加入到一个父视图中,给予父视图合适的大小,再创建MPVolumeView示例,将其加入到父视图中即可,苹果官方的文档1中有示例代码可以参考。

这个方法的缺点如下:

  • UI可定制的的程度低。 MPVolumeView只提供了有限的几个方法来定制其中的Slider和Route Button的样式,而且基本上只能靠换图片解决。如果你想把Slider操作换成Button或者其他的UI组件,那是不可能的。
  • 没有额外的音量控制API。 目前为止没有发现iOS的公开API中有可以直接操作系统音量的,所以修改系统音量只能使用这个UI组件。

如果还想给UI加入手势操作来控制音量,这种直接使用MPVolumeView是做不到的,那么有没有什么方法可以绕过这限制呢?办法还是有的。

编程实现系统音量调节2

上一小节我们提到了MPVolumeView这个组件中,有一个subview来控制音量,即MPVolumeSlider。其实我们可以通过遍历MPVolumeView实例的subviews来得到MPVolumeSlider的实例,从而通过这个UI组件来操作系统音量。

通过MPVolumeSlider的实例来操作系统音量

我们首先通过创建一个MPVolumeView,然后遍历找出MPVolumeSlider的实例。这个实例提供setValue:animated:方法来设置系统音量。我们也可以通过volumeSlider.value这个属性来获取当前的系统音量。具体的代码如下:

MPVolumeView *volumeView = [[MPVolumeView alloc] init];
UISlider* volumeViewSlider = nil;for (UIView *view in [_instance.volumeView subviews]){    if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
        volumeViewSlider = (UISlider*)view;        break;
    }
}// retrieve system volumefloat systemVolume = volumeViewSlider.value;// change system volume, the value is between 0.0f and 1.0f[volumeViewSlider setValue:1.0f animated:NO];// send UI control event to make the change effect right now.[volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];

上面的代码演示如何获取和修改系统音量,注意音量取值为0到1之间的浮点数。

有问题!我不喜欢系统弹出音量提示

上面通过编程的方法可以很完美的调节系统音量,但是每次修改都会弹出系统提示框告知:

有时候这种提示我们未必会需要,那么怎么取消掉这个提示呢?实际上MPVolumeView没有提供任何接口来调节是否需要显示系统音量提示。但是我们发现一点:MPVolumeView处在当前视图的层级之中时,系统就不会显示音量提示。那么事情好办了,我们只要确保两点:

  • MPVolumeView视图处在屏幕上看不见的地方,比如某个不透明视图的下方,或者本视图的非可见区域,一个常见的做法就是把该视图的frame设置为区域以外的地方,比如volumeView.frame = CGRectMake(-1000, -100, 100, 100);
  • 确保MPVolumeView视图的hidden属性值为NO。因为当hidden为YES时,同样会弹出提示。

还有问题,我修改了系统音量但是不是通过我的UI

另一个可能的情况就是用户自己通过硬件的音量调节按钮(位于设备侧边)来调节音量,这种情况会使得你的业务逻辑出现问题,因为你只为自己的App UI写了回调,那么怎么为硬件按钮的事件添加回调呢?我们可以使用Notification Center来完成。
这里只需要监听AVSystemController_SystemVolumeDidChangeNotification事件即可。具体代码如下:

  • 首先在资源载入阶段加入监听事件的代码
NSError *error;// Active audio session before you listen to the volume change event.// It must be called first.// The old style code equivalent to the line below is://// AudioSessionInitialize(NULL, NULL, NULL, NULL);// AudioSessionSetActive(YES);//// Now the code above is deprecated in iOS 7.0, you should use the new// code here.[[AVAudioSession sharedInstance] setActive:YES error:&error];// add event handler, for this example, it is `volumeChange:` method[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
  • 然后实现事件回调方法
- (void)volumeChanged:(NSNotification *)notification
{    // service logic here.}
  • 最后记得在资源回收时取消掉事件监听
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
}

这样,每次用户使用硬件按钮调节音量的时候也会执行你写好的逻辑。

以上除了第一个方案以外,所有的解决方案都属于非官方的hack性质的方法,但是都没有调用私有API,所以没有被Apple审核拒掉的风险。

时间: 2024-09-28 19:05:46

iOS监听音量调节的相关文章

Android 监听音量加减

/** * 监听音量加减 */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_DOWN: Toast.makeText(MainActivity.this, "减", Toast.LENGTH_SHORT).show(); break; case KeyEvent.KEYCODE_VOLUME_UP: To

监听音量上下键调节音量

这个网上貌似很多回答,大多数是转载,监听onkeyDown消息没错,可是好多都没有给出获取当前音量的方法,基本上没法直接用.下面这个测试是有效的. [java] view plaincopy 1.AudioManager audio = (AudioManager) getSystemService(Service.AUDIO_SERVICE); [email protected] 3.public boolean onKeyDown(int keyCode, KeyEvent event) {

ios监听

1.ios中用来监听的方法 代理/通知/block/KVO(监听对象属性变化) 代理:一对一关系,不能用在单例模式?但是为什么不能用在单例模式呢?求解 通知:一对多,发生事件的时候发送通知 KVO:用来监听对象属性的变化(在监听frame时可能会出现问题,具体遇到问题后期我会上代码展示) 2.切记!!通知:发送通知的代码所在的线程,就是通知方法执行的线程!!! 使用的时候需要注意当我们发送了一个通知,想让监听这个通知的对象刷新UI界面,如果该通知不是在 [NSOperationQueue mai

Xamarin Android 监听音量键(下)

上篇在 MainActivity 中重写了按键事件(OnKeyDown),获取了音量键键值并打印了出来,当然,手机物理按键和虚拟按键(音量键.返回键.菜单键等)均可通过该按键事件被捕获. 但是,按键重写在 MainActivity 中,音量键按下时执行的方法在其他页面中. 作者冒出了一个不成熟的想法:利用(publish-subscribe)模式,在 MainActivity 中定义发布者(publish),实例化后层层传递到达 我的页面中,,再将实例化后的订阅者(subscribe)连接上.如

IOS 监听slider滑动

// 监听slider滑动 - (IBAction)valueChnage:(UISlider *)sender; @property (weak, nonatomic) IBOutlet NJView *circleView; @end @implementation NJViewController - (IBAction)valueChnage:(UISlider *)sender { // NSLog(@"%.1f", sender.value); // 1.传递改变后的值给自

ios 监听app从后台恢复到前台

1. APPDelegate中的代理方法可以监听到程序前后台切换的状态 - (void)applicationDidEnterBackground:(UIApplication * )application { NSLog(@"---applicationDidEnterBackground----") // 进入后台 } - (void)applicationDidBecomeActive:(UIApplication * )application { NSLog(@"--

ios 监听TextField中内容变化

本篇文章只为帮助跟多的人.适合初学者. 在这里我介绍3种监听UITextField的方法.并在最后写了一个小的demo 提供参考. -------请不要纠结小编的命名方式规不规范,一切只为共同学习,共同进步. @property (weak, nonatomic) IBOutlet UITextField *UserID; @property (weak, nonatomic) IBOutlet UITextField *Password; @property (weak, nonatomic)

iOS监听tableView组头切换事件

- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section 组头将要出现的时候系统会调用: - (void)tableView:(UITableView *)tableView didEndDisplayingHeaderView:(UIView *)view forSection:(NSInteger)section 组头出现的时候系统

ios监听ScrollView/TableView滚动的正确姿势

主要介绍 监测tableView垂直滚动的舒畅姿势 监测scrollView/collectionView横向滚动的正确姿势 1.监测tableView垂直滚动的舒畅姿势 通常我们用KVO或者在scrollViewDidScroll代理方法中监听ScrollView/TableView的contentOffset,比如监听TableView的contentOffset来设置导航栏的透明度或者拉伸顶部的图片. image image 常见的姿势是在scrollViewDidScroll的代理方法中