转载至:http://www.vanbein.com/posts/ios%E8%BF%9B%E9%98%B6/2015/12/24/tong-guo-dai-ma-diao-zheng-xi-tong-yin-liang-,jian-ting-yin-liang-shi-ti-an-jian/#section-3 最近项目有个功能需要用到监听音量实体键,并能够通过滑动应用内的UISlider调整系统的音量,其中遇到不少问题,所以记录下这个学习过程。
尽管
AVPlayer
和AVPAudiolayer
这些类提供了音量调节功能,但这些音量控制属于App级别的控制。好处就是音量调节独立于系统音量,调节大小时不会影响系统音量。但有时候我们可能希望修改系统音量,以免在调节声音的时候,如果系统音量过小,App调节音量效果不明显。
- (void)registeNotification{images
//1.注册监听系统音量变化,记得在适当的地方移除监听
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(volumeChanged:) name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
//让 UIApplication 开始响应远程的控制,必须添加,不然没效果
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
- (void)volumeChanged:(NSNotification *)notification{
//2.获取到当前音量
float volume = [[[notification userInfo] objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"] floatValue];
//do something here
}
- (void) removeNotification{
//3.移除监听
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
}
//结束远程的控制
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
#### 1.实体键按下的时候,会出现系统的”铃声”,而我想要显示”音量”
这个时候可以添加一句代码,即可让在这个页面时,按下音量实体键显示音量,而不是铃声
//使音量控制实体键响应“音量”而不是”铃声”
[[AVAudioSession sharedInstance] setActive:YES error:NULL];
这是因为程序进入后台后,上述一行代码 [AVAudioSession sharedInstance] 又不再是 Active 状态,所以需要在AppDelegate.m
里面重新设置,这样即可一直响应“音量”了,比如:
AppDelegate.m
- (void)applicationWillEnterForeground:(UIApplication *)application {
//使程序重新激活后,对音量实体键响应为“音量”而不是“铃声”
[[AVAudioSession sharedInstance] setActive:YES error:NULL];
}
这个时候就需要用到 MPVolumeView
了,它不仅可以不显示“音量”,还可以修改设置手机音量。
这个方法是苹果官方推荐的方法。MPVolumeView是
Media Player Framework
中的一个UI组件,直接包含了对系统音量和Airplay设备的音频镜像路由的控制功能。其中包含一个MPVolumeSlider的subview用来控制音量。这个MPVolumeSlider
是一个私有类,我们无法手动创建此类,但这个类是UISlider的子类。MPVolumeView的使用很简单,只需要将其加入到一个父视图中,给予父视图合适的大小,再创建 MPVolumeView 示例,将其加入到父视图中即可,苹果官方的文档中有示例代码可以参考。
这个方法的缺点如下:
实际上MPVolumeView没有提供任何接口来调节是否需要显示系统音量提示。但是我们发现一点:当MPVolumeView处在当前视图的层级之中时,系统就不会显示音量提示。那么事情好办了,我们只要确保两点:
volumeView.frame = CGRectMake(-1000, -100, 100, 100);
hidden
属性值为NO。因为当hidden为YES时,同样会弹出提示。于是想要隐藏”音量提示框”就可以通过添加以下代码实现:
//隐藏"音量提示框"
//注意使用之前需要添加`MediaPlayer.framework`
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, -100, 100, 100)];
volumeView.hidden = NO;
[self.view addSubview:volumeView];
上面我们提到了MPVolumeView这个组件中,有一个subview来控制音量,即MPVolumeSlider。于是我们可以通过遍历 MPVolumeView 实例的subviews来得到MPVolumeSlider的实例,从而通过这个UI组件来操作系统音量。
volumeSlider.value
这个属性来获取当前的系统音量。setValue:animated:
方法来设置系统音量具体的代码如下:
- (void)viewDidLoad {
[super viewDidLoad];
//不显示“铃声”,显示“音量”
[[AVAudioSession sharedInstance] setActive:YES error:NULL];
//1. 获得 MPVolumeView 实例,
MPVolumeView *volumeView = [[MPVolumeView alloc] initWithFrame:CGRectMake(-100, -100, 100, 100)];
//volumeView.hidden = NO;
//[self.view addSubview:volumeView]; //添加后不显示“音量”
volumeViewSlider = nil;
//2. 遍历MPVolumeView的subViews得到MPVolumeSlider
for (UIView *view in [volumeView subviews]){
if ([view.class.description isEqualToString:@"MPVolumeSlider"]){
volumeViewSlider = (UISlider*)view;
break;
}
}
//3.获取系统音量
float systemVolume = volumeViewSlider.value;
//4.添加一个全局的 slider,滑动时同步改变系统音量
VolSlider = [[UISlider alloc] initWithFrame:CGRectMake(30, 200, 300, 20)];
VolSlider.value = systemVolume; //初始值
[VolSlider setMinimumValue:0.0]; //最小值
[VolSlider setMaximumValue:1.0]; //最大值
[VolSlider addTarget:self action:@selector(sliderValueChange:) forControlEvents:UIControlEventValueChanged]; //添加事件
[self.view addSubview:VolSlider];
//注册监听实体键按下事件
[self registeNotification];
}
//
//VolSlider滑动事件
- (void)sliderValueChange:(UISlider *)slider{
//得到当前用户设置的value
float value = slider.value;
//改变系统音量大小,默认音量大小从 0.0 - 1.0
[volumeViewSlider setValue:value animated:NO];
//使setValue立即生效,
[volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];
}
//
//监听音量实体键按下后,响应事件
- (void)volumeChanged:(NSNotification *)notification{
//获取到当前系统音量
float volume = [[[notification userInfo] objectForKey:@"AVSystemController_AudioVolumeNotificationParameter"] floatValue];
//同步设置自定义视图的值
[VolSlider setValue:volume animated:YES];
}
设置后即可使 VolSlider 与系统的音量提示框同步了,效果如下:
附上代码github链接:changeSystemVolume