網(wǎng)易云音樂鎖屏界面實(shí)現(xiàn)

最終效果:
IMG_0931.PNG

完整的實(shí)現(xiàn)思路:

  1. App如果需要在鎖屏界面上顯示相關(guān)的信息和按鈕, 必須先開啟遠(yuǎn)程控制事件(Remote Control Event), 否則鎖屏界面只顯示滑動解鎖.
  2. 實(shí)現(xiàn)鎖屏界面信息, 將歌曲的相關(guān)信息更新到鎖屏界面上
  3. 實(shí)現(xiàn)鎖屏界面的事件處理, 在鎖屏界面和上拉的快速功能菜單中實(shí)現(xiàn)播放控制

遠(yuǎn)程控制事件的實(shí)現(xiàn)

在iOS7.1之前, 遠(yuǎn)程控制事件主要涉及以下三個方法:

  • 開始接收遠(yuǎn)程控制事件
  • 結(jié)束接收遠(yuǎn)程控制事件
  • 觸發(fā)遠(yuǎn)程控制事件后的捕獲處理

官方文檔對這三個方法的描述如下, 這里做了簡單的翻譯.

開始接收遠(yuǎn)程控制事件

Declaration
- (void)beginReceivingRemoteControlEvents

讓App開始接收遠(yuǎn)程控制事件, 該方法屬于UIApplication類

Discussion

在iOS7.1之后, 使用MPRemoteCommandCenter的共享對象來注冊遠(yuǎn)程控制事件. 當(dāng)使用shared command center時, 不需要再調(diào)用該方法.
該方法會開始使用事件響應(yīng)鏈來傳遞遠(yuǎn)程控制事件. 遠(yuǎn)程控制事件是當(dāng)耳機(jī)和外部附件意圖控制App的多媒體表現(xiàn)時發(fā)出的命令. 要停止遠(yuǎn)程控制事件的接收, 必須調(diào)用endReceivingRemoteControlEvents方法

結(jié)束接收遠(yuǎn)程控制事件

Declaration
- (void)endReceivingRemoteControlEvents 

讓App停止接收遠(yuǎn)程控制事件, 該方法屬于UIApplication類

Discussion

在iOS7.1之前, 使用shared MPRemoteCommandCenter對象來注冊遠(yuǎn)程控制事件. 當(dāng)使用shared command center時, 不需要再調(diào)用該方法.
該方法會停止通過事件響應(yīng)鏈來傳遞遠(yuǎn)程控制事件. 遠(yuǎn)程控制事件是當(dāng)耳機(jī)和外部附件意圖控制App的多媒體表現(xiàn)時發(fā)出的命令.

遠(yuǎn)程控制事件的捕獲處理

Declaration
- (void)remoteControlReceivedWithEvent:(UIEvent *)event

當(dāng)遠(yuǎn)程控制事件發(fā)生時觸發(fā)該方法, 該方法屬于UIResponder類

Discussion

遠(yuǎn)程控制事件是由外部附件(包括耳機(jī))所發(fā)出的命令. 應(yīng)用需要響應(yīng)這些命令來控制音頻或視頻媒體的對用戶的表示. 事件響應(yīng)者通過檢查事件的subtype, 來判斷命令的意圖. 比如UIEventSubtypeRemoteControlPlay為播放操作, 然后做相關(guān)處理

要允許遠(yuǎn)程控制事件的傳遞, 需要調(diào)用UIApplication的beginReceivingRemoteControlEvents方法; 要關(guān)閉遠(yuǎn)程控制事件的傳遞則調(diào)用endReceivingRemoteControlEvents

項(xiàng)目中的代碼實(shí)現(xiàn)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 在App啟動后開啟遠(yuǎn)程控制事件, 接收來自鎖屏界面和上拉菜單的控制
    [application beginReceivingRemoteControlEvents];
    
    return YES;
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // 在App要終止前結(jié)束接收遠(yuǎn)程控制事件, 也可以在需要終止時調(diào)用該方法終止
    [application endReceivingRemoteControlEvents];
}

// 在具體的控制器或其它類中捕獲處理遠(yuǎn)程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event
{
    // 根據(jù)事件的子類型(subtype) 來判斷具體的事件類型, 并做出處理
    switch (event.subtype) {
        case UIEventSubtypeRemoteControlPlay:
        case UIEventSubtypeRemoteControlPause: {
            // 執(zhí)行播放或暫停的相關(guān)操作 (鎖屏界面和上拉快捷功能菜單處的播放按鈕)
            break;
        }
        case UIEventSubtypeRemoteControlPreviousTrack: {
            // 執(zhí)行上一曲的相關(guān)操作 (鎖屏界面和上拉快捷功能菜單處的上一曲按鈕)
            break;
        }
        case UIEventSubtypeRemoteControlNextTrack: {
            // 執(zhí)行下一曲的相關(guān)操作 (鎖屏界面和上拉快捷功能菜單處的下一曲按鈕)
            break;
        }
        case UIEventSubtypeRemoteControlTogglePlayPause: {
            // 進(jìn)行播放/暫停的相關(guān)操作 (耳機(jī)的播放/暫停按鈕)
            break;
        }
        default:
            break;
    }
}

iOS7.1后, 更新了遠(yuǎn)程控制事件的實(shí)現(xiàn)方式

相關(guān)方法的描述中, 已經(jīng)說明, iOS7.1之后使用MPRemoteCommandCenter類來進(jìn)行遠(yuǎn)程控制事件的相關(guān)處理, 因此可以不再使用上面所描述的三個方法. 官方文檔對MPRemoteCommandCenter的描述如下:

MPRemoteCommandCenter

MPRemoteCommandCenter類提供了處理遠(yuǎn)程控制事件的對象, 包括由外部附件和系統(tǒng)傳輸控制發(fā)送的遠(yuǎn)程控制事件. 不需要自己創(chuàng)建該類的實(shí)例. 而是使用shareCommandCenter方法獲取默認(rèn)的命令中心(share command center)對象. share command center對象的屬性包含了MPRemoteCommand對象(表示iOS支持的每種遠(yuǎn)程控件事件). 如果要對響應(yīng)的事件特殊處理, 使用適當(dāng)?shù)腗PRemoteCommand對象注冊一個handler即可.

遠(yuǎn)程命令中心(remote command center)對象為許多不同類型的事件提供了命令(command)對象. 如果你的App不需要支持某些特定類型的事件, 可以通過設(shè)置其enabled屬性為NO來禁用關(guān)聯(lián)的MPRemoteCommand對象. 使用command對象注冊一個handler, 以便讓系統(tǒng)知道你的App已經(jīng)做好了接收事件的準(zhǔn)備. 只有當(dāng)你的App是當(dāng)前正在播放(Now Playing App)時才能接收到事件的傳遞.

項(xiàng)目中的代碼實(shí)現(xiàn) :

// 在需要處理遠(yuǎn)程控制事件的具體控制器或其它類中實(shí)現(xiàn)
- (void)remoteControlEventHandler
{
    // 直接使用sharedCommandCenter來獲取MPRemoteCommandCenter的shared實(shí)例
    MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];

    // 啟用播放命令 (鎖屏界面和上拉快捷功能菜單處的播放按鈕觸發(fā)的命令)
    commandCenter.playCommand.enabled = YES;
    // 為播放命令添加響應(yīng)事件, 在點(diǎn)擊后觸發(fā)
    [commandCenter.playCommand addTarget:self action:@selector(playAction:)];

    // 播放, 暫停, 上下曲的命令默認(rèn)都是啟用狀態(tài), 即enabled默認(rèn)為YES
    // 為暫停, 上一曲, 下一曲分別添加對應(yīng)的響應(yīng)事件
    [commandCenter.pauseCommand addTarget:self action:@selector(pauseAction:)];
    [commandCenter.previousTrackCommand addTarget:self action:@selector(previousTrackAction:)];
    [commandCenter.nextTrackCommand addTarget:self action:@selector(nextTrackAction:)];

    // 啟用耳機(jī)的播放/暫停命令 (耳機(jī)上的播放按鈕觸發(fā)的命令)
    commandCenter.togglePlayPauseCommand.enabled = YES;
    // 為耳機(jī)的按鈕操作添加相關(guān)的響應(yīng)事件
    [commandCenter.togglePlayPauseCommand addTarget:self action:@selector(playOrPauseAction:)];
}
效果如圖:

IMG_0935.PNG

鎖屏界面相關(guān)信息更新

實(shí)現(xiàn)了遠(yuǎn)程控制事件后, App在進(jìn)行音樂播放時, 上拉快捷功能菜單都會提供遠(yuǎn)程控件按鈕, 鎖屏界面會有改動, 出現(xiàn)遠(yuǎn)程控制按鈕, 以及歌曲進(jìn)度等信息, 接下來需要將歌曲的相關(guān)信息更新到鎖屏界面上. 主要通過MPNowPlayingInfoCenter類來實(shí)現(xiàn), 下面是官方文檔的描述:

MPNowPlayingInfoCenter

使用now playing info center來設(shè)置App當(dāng)前正在播放的媒體文件的信息(now-playing information).

系統(tǒng)會在設(shè)備的鎖屏界面和上劃的快捷控制面板的多媒體控制部分顯示當(dāng)前播放文件的信息. 如果用戶直接通過AirPlay在Apple TV上播放媒體文件時, now-playing信息會顯示在電視屏幕上. 如果用戶將設(shè)備連接到iPad附件, 比如汽車(通過CarPlay連接)上, 附件上可能會顯示now-playing的信息.

你不能直接控制哪些信息要被顯示出來, 以及這些信息顯示的樣式. 只需要設(shè)置now playing info center dictionary的相關(guān)value, 將這些相關(guān)信息提交給系統(tǒng)即可. 系統(tǒng)或已經(jīng)連接的附件, 會用一致的方式為所有的App處理這些信息的展示.

可以配置的鎖屏界面信息

可以使用的information屬性, 是定義在MPMediaItem類的General Media Item Property Keys屬性中的子集(即其中的某些屬性). 在iOS5.0后, now playing info center支持下列media item屬性的Key: (僅列舉了常用的Key!)

  • MPMediaItemPropertyAlbumTitle
    專輯的標(biāo)題, value是NSString對象
  • MPMediaItemPropertyArtist
    media item的創(chuàng)作者, value是NSString對象
  • MPMediaItemPropertyArtwork
    media item的插圖. value是MPMediaItemArtwork類的對象
  • MPMediaItemPropertyPlaybackDuration
    media item的播放總時長. value是表示包裝了時長秒數(shù)(NSTimeInterval)的NSNumber類型
  • MPMediaItemPropertyTitle
    media item的名字或標(biāo)題. 該屬性與MPMediaItemPropertyAlbumTitle屬性無關(guān), value是NSString對象

額外添加的一些可以使用的屬性在MPNowPlayingInfoCenter類的描述文檔中的Additional Metadata Properties中作了聲明. (僅列舉了常用的Key!)

  • MPNowPlayingInfoPropertyElapsedPlaybackTime
    當(dāng)前播放的item所消逝的時間(歌曲當(dāng)前時間), 單位為秒. value是包裝了double值的NSNumber對象. elapsed time是由系統(tǒng)根據(jù)之前提供elapsed tiime和playback rate進(jìn)行自動進(jìn)行計(jì)算的. 請不要頻繁的更新該屬性, 這是沒有必要的.
  • MPNowPlayingInfoPropertyPlaybackRate
    當(dāng)前播放的item的播放速率, value為1.0表示正常的播放速率. value是包裝了double值的NSNumber對象. 默認(rèn)值是1.0. playback rate的值為2.0表示普通播放速率的2倍; 此時media從播放到結(jié)束只需要一半時間.

項(xiàng)目中的代碼實(shí)現(xiàn)

- (void)updatelockScreenInfo 
{
    // 直接使用defaultCenter來獲取MPNowPlayingInfoCenter的默認(rèn)唯一實(shí)例
    MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];

    // MPMediaItemArtwork 用來表示鎖屏界面圖片的類型
    MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc]     initWithImage:image];

    // 通過配置nowPlayingInfo的值來更新鎖屏界面的信息
    infoCenter.nowPlayingInfo = @{
                                  // 歌曲名
                                  MPMediaItemPropertyTitle : music.name,
                                  // 藝術(shù)家名
                                  MPMediaItemPropertyArtist : music.singer,
                                  // 專輯名字
                                  MPMediaItemPropertyAlbumTitle : music.album,
                                  // 歌曲總時長 
                                  MPMediaItemPropertyPlaybackDuration : @(duration),
                                  // 歌曲的當(dāng)前時間
                                  MPNowPlayingInfoPropertyElapsedPlaybackTime : @(currentTime),
                                  // 歌曲的插圖, 類型是MPMeidaItemArtwork對象
                                  MPMediaItemPropertyArtwork : artwork,
                                  
                                  // 無效的, 歌詞的展示是通過圖片繪制完成的, 即將歌詞繪制到歌曲插圖, 通過更新插圖來實(shí)現(xiàn)歌詞的更新的
                                  // MPMediaItemPropertyLyrics : lyric.content,
                                  };
}
效果如圖:

IMG_0934.PNG

類似網(wǎng)易新聞的鎖屏控制按鈕實(shí)現(xiàn)

通過上述代碼實(shí)現(xiàn)后, 鎖屏界面已經(jīng)可以展示出歌曲信息與控制按鈕, 通過按鈕或耳機(jī)的按鍵也可以實(shí)現(xiàn)相關(guān)的控制效果. 但網(wǎng)易的控制按鈕中最左邊并是上一曲, 而是列表按鈕, 點(diǎn)擊后還能在鎖屏界面彈出一個ActionSheet界面. 該功能其實(shí)是通過修改MPRemoteCommandCenter的反饋功能(提供喜歡, 不喜歡, 標(biāo)記(bookmark)操作)來實(shí)現(xiàn)的.

涉及到的反饋功能, 先了解MPFeedbackCommond這個類, 以下是文檔的描述

MPFeedbackCommond

MPFeedbackCommand對象反映了當(dāng)前App所播放的反饋狀態(tài). MPRemoteCommandCenter對象提供feedback對象用于對媒體文件進(jìn)行喜歡, 不喜歡, 標(biāo)記的操作. 使用這些對象為App支持的回饋(feedback)方式進(jìn)行注冊handler, 并在反饋狀態(tài)修改時執(zhí)行適當(dāng)?shù)娜蝿?wù)(task). 在當(dāng)前播放的item改變時, 也可以使用該對象為新的item設(shè)置反饋狀態(tài).

當(dāng)item的反饋狀態(tài)改變時, 系統(tǒng)傳遞適當(dāng)?shù)氖录皆搶ο笞缘膆andler上. handler的代碼必須決定哪一個media item來接收反饋, 然后再為該item執(zhí)行更新反饋狀態(tài)的操作. 你也可以執(zhí)行與接收到反饋相關(guān)的其它任務(wù). 比如, 當(dāng)用戶喜歡當(dāng)前播放的歌曲時你可能要在UI上做出適當(dāng)調(diào)整, 并使用該信息來進(jìn)行相關(guān)歌曲的推薦.

MPRemoteCommandCenterr提供了相關(guān)屬性(反饋按鈕)

@property (nonatomic, readonly) MPFeedbackCommand *likeCommand;  // 喜歡命令
@property (nonatomic, readonly) MPFeedbackCommand *dislikeCommand;  // 不喜歡命令
@property (nonatomic, readonly) MPFeedbackCommand *bookmarkCommand; // 標(biāo)記(書簽)命令

事實(shí)上, 系統(tǒng)的鎖屏界面并不支持自定義. 這里邊只需要添加反饋按鈕, 則系統(tǒng)默認(rèn)的鎖屏界面就是網(wǎng)易云音樂所展示的樣式. 包括點(diǎn)擊后彈出的ActionSheet都是系統(tǒng)針對反饋按鈕所提供了, 網(wǎng)易云音樂只是巧妙的將"不喜歡"按鈕的標(biāo)題修改成"上一曲", 并在該按鈕的響應(yīng)事件里實(shí)現(xiàn)上一曲的代碼, 即完成相關(guān)功能.

項(xiàng)目中的代碼實(shí)現(xiàn)

// 添加"喜歡"按鈕, 需要啟用, 并且設(shè)置了相關(guān)Action后才會生效
[MPRemoteCommandCenter sharedCommandCenter].likeCommand.enabled = YES;
[[MPRemoteCommandCenter sharedCommandCenter].likeCommand addTarget:self action:@selector(likeItemAction)];
[MPRemoteCommandCenter sharedCommandCenter].likeCommand.localizedTitle = @"喜歡";

// 添加"不喜歡"按鈕
[MPRemoteCommandCenter sharedCommandCenter].dislikeCommand.enabled = YES;
// 自定義該按鈕的響應(yīng)事件, 實(shí)現(xiàn)在點(diǎn)擊"不喜歡"時去執(zhí)行上一首的功能
[[MPRemoteCommandCenter sharedCommandCenter].dislikeCommand 
addTarget:self action:@selector(previousCommandAction)];
[MPRemoteCommandCenter
// 自定義"不喜歡"的標(biāo)題, 偽裝成"上一首"
sharedCommandCenter].dislikeCommand.localizedTitle = @"上一首";

注意: 反饋按鈕默認(rèn)不啟用, 因此需要將enabled設(shè)置為YES, 同時必須添加對應(yīng)的響應(yīng)事件, 按鈕才會在鎖屏界面顯示.

完成效果:
IMG_0930.PNG
IMG_0932.PNG

IMG_0931.PNG

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凳干,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子断傲,更是在濱河造成了極大的恐慌括堤,老刑警劉巖碌秸,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異悄窃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蹂窖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門轧抗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瞬测,你說我怎么就攤上這事横媚。” “怎么了月趟?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵灯蝴,是天一觀的道長。 經(jīng)常有香客問我孝宗,道長穷躁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任因妇,我火速辦了婚禮问潭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘婚被。我一直安慰自己狡忙,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布址芯。 她就那樣靜靜地躺著灾茁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谷炸。 梳的紋絲不亂的頭發(fā)上北专,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音淑廊,去河邊找鬼逗余。 笑死,一個胖子當(dāng)著我的面吹牛季惩,可吹牛的內(nèi)容都是我干的录粱。 我是一名探鬼主播腻格,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼啥繁!你這毒婦竟也來了菜职?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤旗闽,失蹤者是張志新(化名)和其女友劉穎酬核,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體适室,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嫡意,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了捣辆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔬螟。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖汽畴,靈堂內(nèi)的尸體忽然破棺而出旧巾,到底是詐尸還是另有隱情,我是刑警寧澤忍些,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布鲁猩,位于F島的核電站,受9級特大地震影響罢坝,放射性物質(zhì)發(fā)生泄漏廓握。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一炸客、第九天 我趴在偏房一處隱蔽的房頂上張望疾棵。 院中可真熱鬧,春花似錦痹仙、人聲如沸是尔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拟枚。三九已至,卻和暖如春众弓,著一層夾襖步出監(jiān)牢的瞬間恩溅,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工谓娃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脚乡,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓滨达,卻偏偏與公主長得像奶稠,于是被迫代替她去往敵國和親俯艰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容