1. 程式人生 > >iOS --- 音量調節檢視MPVolumeView的使用

iOS --- 音量調節檢視MPVolumeView的使用

在之前的一篇文章 iOS — 使用AVFoundation的AVAudioPlayer來播放音訊中,簡單介紹了AVAudioPlayer的使用。其中通過AVAudioPlayer物件例項的volume屬性可以調節該APP的音量大小。但不會影響到iOS系統音量。那如果要對系統音量進行調節呢?

MPVolumeView

MPVolumeView是MediaPlayer框架中的一個元件,包含了對系統音量和AirPlay裝置的音訊映象路由的控制功能。MPVolumeView有三個subview,其中私有類(無法手動建立,也無法使用isKindOfClass方法)MPVolumeSlider用來控制音量大小,繼承自UISlider。
另外還有UILabel和MPButton兩個subview,暫時沒有使用到。
將MPVolumeView物件例項當做一個subview,新增到父view中即可使用,但其UI可定製性很低。使用前要import MediaPlayer。

if (mpVolumeView == nil) {
    volumeLabel = UILabel(frame: CGRectMake(0, 100, self.view.frame.width, 30))
    volumeLabel.textAlignment = NSTextAlignment.Center
    self.view.addSubview(volumeLabel)

    mpVolumeView = MPVolumeView(frame: CGRectMake(20, 150, self.view.frame.width - 40, 30))
    self.view
.addSubview(mpVolumeView) for var view: UIView in mpVolumeView.subviews { print(view.description) if (NSStringFromClass(view.classForCoder) == "MPVolumeSlider") { volumeSlider = view as! UISlider; volumeSlider.sendActionsForControlEvents(.TouchUpInside) } } }

volumeSlider就呈現在MPVolumeView的位置上,其值對應當前的系統音量。

這裡寫圖片描述

關於上邊實現0.0的volumeLabel,大家可以不必關心,未將其與系統音量值繫結起來而已。
關於這句判斷, Swift和Objective-C的方式不一樣:

// Swift
if (NSStringFromClass(view.classForCoder) == "MPVolumeSlider") {
// Objective-C:
if ([view.class.description isEqualToString:@"MPVolumeSlider"]) {

使用系統音量鍵調節音量

經過以上步驟之後,通過系統音量鍵調節音量大小的時候,也能控制_volumeSlider的值。
但會有一個問題:

這裡寫圖片描述

即系統音量提示會出來干擾,那這種對螢幕的遮蓋在一些場合是要去掉的,如拍照等。
其實,這裡有兩個場景:

  1. 裝置後臺有背景音樂正在播放(如QQ音樂等)
  2. 裝置後臺沒有背景音樂播放

對於場景1,系統音量提示則會隱藏掉。但是對於場景2,系統音量提示會自動呈現出來。
如何去除該提示呢?嘗試了很久找到了下邊的方法:

if AVAudioSession.sharedInstance().otherAudioPlaying {
    // 場景1
    do {
        try AVAudioSession.sharedInstance().setActive(false)
    } catch {
    }
} else {
    // 場景2
    do {
        try AVAudioSession.sharedInstance().setActive(true)
    } catch {
    }
}

使用AVAudioSession來判斷當前是否有背景音樂播放,然後對於場景2,設定當前AVAudioSession為active即可隱藏系統音量提示。
暫時不知道還有沒有其他更好的方法?
這裡提供了一種方法,但經過試驗,並不適用該場景。

對於Objective-C的寫法:

AVAudioSession *audioSession = [AVAudioSession sharedInstance];
NSError *error = nil;
if (audioSession.otherAudioPlaying) {
    [audioSession setActive:NO error:&error];
} else {
    [audioSession setActive:YES error:&error];
}

監聽系統音量變化

使用通知AVSystemController_SystemVolumeDidChangeNotification即可監控系統音量變換,

NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("volumeChanged:"), name: "AVSystemController_SystemVolumeDidChangeNotification", object: nil)

記得用完取消監聽就好了。

AVAudioSession

AVAudioSession是AVFoundation框架引入的,常用其setCategory方法設定音訊屬性。

[audioSession setCategory:AVAudioSessionCategoryAmbient withOptions:AVAudioSessionCategoryOptionMixWithOthers error:&error];

可選屬性如下:

#pragma mark -- Values for the category property --

/*  Use this category for background sounds such as rain, car engine noise, etc.  
 Mixes with other music. */
AVF_EXPORT NSString *const AVAudioSessionCategoryAmbient;

/*  Use this category for background sounds.  Other music will stop playing. */
AVF_EXPORT NSString *const AVAudioSessionCategorySoloAmbient;

/* Use this category for music tracks.*/
AVF_EXPORT NSString *const AVAudioSessionCategoryPlayback;

/*  Use this category when recording audio. */
AVF_EXPORT NSString *const AVAudioSessionCategoryRecord;

/*  Use this category when recording and playing back audio. */
AVF_EXPORT NSString *const AVAudioSessionCategoryPlayAndRecord;

/*  Use this category when using a hardware codec or signal processor while
 not playing or recording audio. */
AVF_EXPORT NSString *const AVAudioSessionCategoryAudioProcessing;

AVF_EXPORT NSString *const AVAudioSessionCategoryMultiRoute NS_AVAILABLE_IOS(6_0);

Demo