QQ音樂播放器,歌詞同步

源代碼下載路徑:https://pan.baidu.com/s/1dES8wfR?因?yàn)槔锩娲a中包含的資源過多,沒有上傳到我的github賬號(hào)中,直接保存在百度云盤中。

? ? ? ?這兩天工作上沒什么事,模仿QQ音樂播放器寫了個(gè)簡(jiǎn)單的QQ音樂播放界面,可以實(shí)現(xiàn)歌詞同步功能。另外這個(gè)Demo中還設(shè)置了后臺(tái)鎖屏播放界面模式,處于鎖屏狀態(tài)下同樣可以像QQ音樂那樣自如切換,以及顯示歌詞。

? ? ? ? 看一下震撼的效果圖:


效果圖

? ? ? ?接下來這篇文章主要是分析一下本人認(rèn)為有必要說明的幾個(gè)點(diǎn)。分別是:滑動(dòng)的時(shí)候顯示歌詞界面問題、歌詞按照音樂播放的進(jìn)度逐漸顯示為綠色的實(shí)現(xiàn)、播放界面imageView旋轉(zhuǎn)和暫停動(dòng)畫問題、鎖屏界面信息配置。可能有人認(rèn)為控制播放界面imageView旋轉(zhuǎn)和暫停動(dòng)畫是非常簡(jiǎn)單的事情,確實(shí)簡(jiǎn)單,但是有沒有想過如何通過核心動(dòng)畫去控制動(dòng)畫的暫停和開始。

1.如何在手指向右滑動(dòng)的時(shí)候顯示歌詞界面?

? ? ? 這個(gè)其實(shí)很簡(jiǎn)單,但是如果沒有做過類似這樣app的開發(fā)人員,可能認(rèn)為就是在界面上添加一個(gè)滑動(dòng)的手勢(shì),然后通過判斷手勢(shì)的滑動(dòng)方向,來控制歌詞界面的展示和隱藏。這樣做雖然可以實(shí)現(xiàn)同樣的目的,但是會(huì)過于麻煩。最好的做法是借助UIScrollView控件,直接通過劃過scroollView來展示和隱藏歌詞界面,這種做法干脆利落簡(jiǎn)便。目前很火熱的一些直播類app的聊天互動(dòng)界面其實(shí)也都是通過這樣的方式完成的。在滑動(dòng)scrooView的時(shí)候,我們還可以通過scroollView的代理方法設(shè)置播放界面的透明度,使界面更加美觀。

2.如何通過核心動(dòng)畫控制播放界面imageView旋轉(zhuǎn)和暫停動(dòng)畫?

? ? ? ?可能以前用核心動(dòng)畫的時(shí)候一直沒有涉及到動(dòng)畫的暫停和開始,可是當(dāng)我用核心動(dòng)畫來設(shè)置動(dòng)畫效果,當(dāng)音樂播放暫停的時(shí)候要停止動(dòng)畫效果。這時(shí)一下子就懵了,怎樣實(shí)現(xiàn)呢。于是在網(wǎng)上找到了解決方案。正確的做法是創(chuàng)建一個(gè)CALayer的分類,然后再源文件中實(shí)現(xiàn)以下代碼:

- (void)pauseAnimate

{

? ? ? ? CFTimeInterval pausedTime = [self convertTime:CACurrentMediaTime() fromLayer:nil];

? ? ? ? self.speed = 0.0;

? ? ? ? self.timeOffset = pausedTime;

}

- (void)resumeAnimate

{

? ? ? ? ? ?CFTimeInterval pausedTime = [self timeOffset];

? ? ? ? ?self.speed = 1.0;

? ? ? ? ?self.timeOffset = 0.0;

? ? ? ? ? self.beginTime = 0.0;

? ? ? ? ? ?CFTimeInterval timeSincePause = [self convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;

? ? ? ? self.beginTime = timeSincePause;

}

? ? ? ?上面第一個(gè)方法是暫停動(dòng)畫,第二個(gè)方法是開始動(dòng)畫。這個(gè)類別可以保存起來,以后碰到其他類似問題,照舊可以拿來使用。

3.歌詞如何實(shí)現(xiàn)和播放的進(jìn)度同步?

? ? ? 這里主要講解綠色文字如何和歌詞實(shí)現(xiàn)同步。至于每一句歌詞如何和歌詞同步就簡(jiǎn)單說下,主要是通過定時(shí)器完成,要解析歌詞每一句對(duì)應(yīng)的時(shí)間和文字。綠色文字的同步看起來課高大上,實(shí)際上很簡(jiǎn)單,代碼量也就簡(jiǎn)短的數(shù)行。首先要知道,每一行歌詞是借助UILabel顯示的,要想事項(xiàng)綠色文字和歌詞同步,我們只需要自定義自己的label類即可,但是毋庸置疑這個(gè)自定的這個(gè)label類要有一個(gè)進(jìn)度progress屬性。看一下這個(gè)自定義label的源碼。

.h文件實(shí)現(xiàn)

#import@interface ZWLrcLabel : UILabel

/*當(dāng)前播放的進(jìn)度*/

@property(nonatomic,assign)CGFloat progress;

@end

.m文件實(shí)現(xiàn)

#import "ZWLrcLabel.h"

@implementation ZWLrcLabel

- (void)drawRect:(CGRect)rect {

? ? ? ? ?[super drawRect:rect];?

? ? ? ? CGRect fillRect = CGRectMake(0, 0, self.bounds.size.width * self.progress, self.bounds.size.height);

? ? ? [[UIColor greenColor] set];

? ? ? // UIRectFill(fillRect);

? ? ? ?UIRectFillUsingBlendMode(fillRect, kCGBlendModeSourceIn);

}

- (void)setProgress:(CGFloat)progress{

? ? ? ? ?_progress = progress;

? ? ? ? [self setNeedsDisplay];

}

代碼中UIRectFillUsingBlendMode(fillRect, kCGBlendModeSourceIn);是實(shí)現(xiàn)播放進(jìn)度和綠色歌詞文字同步的核心。UIRectFill(fillRect);是label背景色的變化,這行代碼用不到,在這里只是提一下,有興趣的可以看看具體實(shí)現(xiàn)效果。調(diào)用[self setNeedsDisplay];這句代碼就會(huì)調(diào)用- (void)drawRect:(CGRect)rect方法。

4.鎖屏狀態(tài)歌曲播放切換,以及界面顯示是如何自定義的?

首先要想實(shí)現(xiàn)歌詞鎖屏狀態(tài)界面的相關(guān)配置,首先必然要開啟后臺(tái)音頻回話。應(yīng)該在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;添加以下三行代碼:

? ? ? ? //1.獲取音頻會(huì)話

? ? ? ?AVAudioSession *session = [AVAudioSession sharedInstance];

? ? ? ? //2.設(shè)置后臺(tái)類型

? ? ? [session setCategory:AVAudioSessionCategoryPlayback error:nil];

? ? ? ?//3.激活回話

? ? ? ?[session setActive:YES error:nil];

? ? ? 接下來,先看一下鎖屏界面信息(如圖片,歌曲名,歌手名,時(shí)長(zhǎng)等)配置是如何實(shí)現(xiàn)的,代碼中有注釋。以下代碼在歌曲開始播放的時(shí)候,直接調(diào)用即可。

- (void)setupLockScreenInfo{

? ? ? ? ?//0.獲取當(dāng)前播放的歌曲

? ? ? ? ZWMusicModel *playingMusic = [ZWMusicTool playingMusic];

? ? ? ?//1.獲取鎖屏中心

? ? ? ?MPNowPlayingInfoCenter *playingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];?

? ? ? ?//2、設(shè)置屏幕參數(shù)

? ? ? ? NSDictionary *playingInfoDict = [NSMutableDictionary dictionary];

? ? ? ?//2.1設(shè)置歌曲名

? ? ? ?[playingInfoDict setValue:playingMusic.name forKey:MPMediaItemPropertyAlbumTitle];

? ? ? //2.2設(shè)置歌手名

? ? ? ?[playingInfoDict setValue:playingMusic.singer forKey:MPMediaItemPropertyArtist];

? ? ? ?//2.3設(shè)置封面圖片?

? ? ? ?MPMediaItemArtwork *artWork = [[MPMediaItemArtwork alloc]initWithImage:[UIImage imageNamed:playingMusic.icon]];

? ? ? ?[playingInfoDict setValue:artWork forKey:MPMediaItemPropertyArtwork];

? ? ? ?//2.4歌曲的總時(shí)長(zhǎng)

? ? ? ?[playingMusic setValue:@(self.currentPlayer.duration) forKey:MPMediaItemPropertyPlaybackDuration];

? ? ? ?playingInfoCenter.nowPlayingInfo = playingInfoDict;

? ? ? ? //3.開啟遠(yuǎn)程交互

? ? ? ?[[UIApplication sharedApplication]beginReceivingRemoteControlEvents];

}

最后再來看看如何實(shí)現(xiàn)后臺(tái)的遠(yuǎn)程交互,控制音樂的播放暫停,下一曲等。這里要注意兩點(diǎn):a、- (void)remoteControlReceivedWithEvent:(UIEvent *)event是一個(gè)系統(tǒng)方法。b、要想要這個(gè)系統(tǒng)方法生效,在配置鎖屏界面UI相關(guān)信息的時(shí)候,要開啟遠(yuǎn)程交互,即[[UIApplication sharedApplication]beginReceivingRemoteControlEvents];

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

? ? ? ?switch (event.subtype) {

? ? ? ? ? ? ? ? ? case UIEventSubtypeRemoteControlPlay:

? ? ? ? ? ? ? ? ? case UIEventSubtypeRemoteControlPause:

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [self playOrPause:self.playButton];//播放或暫停的方法

? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? ?case UIEventSubtypeRemoteControlNextTrack:?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? [self next:self.nextButton];//下一曲的方法

? ? ? ? ? ? ? ? ?break;

? ? ? ? ? ? ? ? ?case? UIEventSubtypeRemoteControlPreviousTrack:

? ? ? ? ? ? ? ? ? ? ? ? ? [self next:self.previousButton];//上一曲的方法

? ? ? ? ? ? ? ? ?break;

? ? ? ? ? ? ? ? ?default:

? ? ? ? ? ? ? ? ?break;

? ? ? }

}

就簡(jiǎn)單介紹到這里,源代碼中有注釋,可以結(jié)合這篇文章和源代碼一塊學(xué)習(xí)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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