通過程式碼調整系統音量,監聽音量實體按鍵事件
儘管
AVPlayer
和AVPAudiolayer
這些類提供了音量調節功能,但這些音量控制屬於App級別的控制。好處就是音量調節獨立於系統音量,調節大小時不會影響系統音量。但有時候我們可能希望修改系統音量,以免在調節聲音的時候,如果系統音量過小,App調節音量效果不明顯。
一、監聽手機實體音量按鍵
- 和監聽鍵盤彈出類似的,Apple提供了一個通知給我們,只要在合適的地方新增對這個通知的監聽即可。
- (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];
2.出現了”音量”,但是因鎖屏、進入後臺等原因 ResignActive 重新啟用後,又顯示了”鈴聲”而不是”音量”
這是因為程式進入後臺後,上述一行程式碼 [AVAudioSession sharedInstance] 又不再是 Active 狀態,所以需要在AppDelegate.m
裡面重新設定,這樣即可一直響應“音量”了,比如:
AppDelegate.m
- (void)applicationWillEnterForeground:(UIApplication *)application {
//使程式重新啟用後,對音量實體鍵響應為“音量”而不是“鈴聲”
[[AVAudioSession sharedInstance] setActive:YES error:NULL];
}
3.我不想出現”音量”
這個時候就需要用到MPVolumeView
了,它不僅可以不顯示“音量”,還可以修改設定手機音量。
這個方法是蘋果官方推薦的方法。MPVolumeView是
Media Player Framework
中的一個UI元件,直接包含了對系統音量和Airplay裝置的音訊映象路由的控制功能。其中包含一個MPVolumeSlider的subview用來控制音量。這個MPVolumeSlider
是一個私有類,我們無法手動建立此類,但這個類是UISlider的子類。MPVolumeView的使用很簡單,只需要將其加入到一個父檢視中,給予父檢視合適的大小,再建立 MPVolumeView 示例,將其加入到父檢視中即可,蘋果官方的文件中有示例程式碼可以參考。
-
這個方法的缺點如下:
- UI可定製的的程度低。 MPVolumeView只提供了有限的幾個方法來定製其中的Slider和Route Button的樣式,而且基本上只能靠換圖片解決。如果你想把Slider操作換成Button或者其他的UI元件,那是不可能的。
- 沒有額外的音量控制API。 目前為止沒有發現iOS的公開API中有可以直接作業系統音量的,所以修改系統音量只能使用這個UI元件。如果還想給UI加入手勢操作來控制音量,這種直接使用MPVolumeView 是做不到的,那麼有沒有什麼方法可以繞過這限制呢?辦法還是有的。
-
實際上MPVolumeView沒有提供任何介面來調節是否需要顯示系統音量提示。但是我們發現一點:當MPVolumeView處在當前檢視的層級之中時,系統就不會顯示音量提示。那麼事情好辦了,我們只要確保兩點:
- MPVolumeView檢視處在螢幕上看不見的地方,比如某個不透明檢視的下方,或者本檢視的非可見區域,一個常見的做法就是把該檢視的frame設定為區域以外的地方,比如
volumeView.frame = CGRectMake(-1000, -100, 100, 100);
- 確保MPVolumeView檢視的
hidden
屬性值為NO。因為當hidden為YES時,同樣會彈出提示。
- MPVolumeView檢視處在螢幕上看不見的地方,比如某個不透明檢視的下方,或者本檢視的非可見區域,一個常見的做法就是把該檢視的frame設定為區域以外的地方,比如
於是想要隱藏”音量提示框”就可以通過新增以下程式碼實現:
//隱藏"音量提示框"
//注意使用之前需要新增`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元件來作業系統音量。
- 步驟如下:
- 1.通過建立一個MPVolumeView
- 2.遍歷找出MPVolumeSlider的例項
- 3.可以通過
volumeSlider.value
這個屬性來獲取當前的系統音量。 - 4.這個例項提供
setValue:animated:
方法來設定系統音量 - 5.新增一個自定義的檢視比如一個slider,通過這個檢視來改變系統音量
具體的程式碼如下:
- (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 與系統的音量提示框同步了,效果如下: