1. 程式人生 > >通過程式碼調整系統音量,監聽音量實體按鍵事件

通過程式碼調整系統音量,監聽音量實體按鍵事件

儘管AVPlayerAVPAudiolayer這些類提供了音量調節功能,但這些音量控制屬於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時,同樣會彈出提示。

於是想要隱藏”音量提示框”就可以通過新增以下程式碼實現:

//隱藏"音量提示框"
//注意使用之前需要新增`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 與系統的音量提示框同步了,效果如下:

同步效果