iOS開(kāi)發(fā)手記-仿QQ音樂(lè)播放器動(dòng)態(tài)歌詞的實(shí)現(xiàn)

最近朋友想做個(gè)音樂(lè)App四苇,讓我?guī)兔⒖枷乱押АF渲懈柙~動(dòng)態(tài)滾動(dòng)的效果离钝,正好我之前也沒(méi)做過(guò),順便學(xué)習(xí)一下褪储,先來(lái)個(gè)預(yù)覽效果卵渴。

demo

實(shí)現(xiàn)思路

歌詞常見(jiàn)的就是lrc歌詞了,我們這里也是通過(guò)解析lrc歌詞文件來(lái)獲取其播放參數(shù)鲤竹,以實(shí)現(xiàn)和播放器協(xié)同浪读。下面是我從百度音樂(lè)獲取的歌詞文件示例:

```[ti:冰雨]`
[ar:劉德華]
[al:笨小孩]
[00:0.05]冰雨
[00:0.94]作詞:劉德華、李密 作曲:潘協(xié)慶
[00:01.23]演唱:劉德華

[00:01.37]
[00:04.79](歌手獨(dú)白)
[00:17.18]我是在等待 一個(gè)女孩
[00:25.18]還是在等待沉淪苦海
[00:32.91]一個(gè)人靜靜發(fā)呆 沒(méi)有人去管花謝花開(kāi)
[00:41.03]無(wú)法肯定的愛(ài) 左右搖擺
[00:45.43]只好把心酸往深心里塞
[00:49.61]我是在等待 你的回來(lái)
[00:57.73]難道只換回一句活該
[01:05.27]一個(gè)人靜靜發(fā)呆
[01:09.18]兩個(gè)人卻有不同無(wú)奈
[01:13.15]好好的一份愛(ài) 啊怎么會(huì)慢慢變壞
[01:18.43]
[01:20.44]冷冷的冰雨在臉上胡亂的拍
[01:24.31]暖暖的眼淚跟寒雨混成一塊
[01:28.32]眼前的色彩忽然被掩蓋
[01:32.28]你的影子無(wú)情在身邊徘徊
[01:36.30]你就像一個(gè)劊子手把我出賣
[01:40.35]我的心彷佛被剌刀狠狠地宰
[01:44.36]在懸崖上的愛(ài) 誰(shuí)會(huì)愿意接受最痛的意外
[01:51.09]
[02:26.59]我是在等待你的回來(lái)
[02:35.52]難道只換回一句活該
[02:42.99]一個(gè)人靜靜發(fā)呆
[02:46.99]兩個(gè)人卻有不同無(wú)奈
[02:51.08]好好的一份愛(ài) 啊怎么會(huì)慢慢變壞
[02:56.42]
[02:58.54]冷冷的冰雨在臉上胡亂的拍
[03:02.41]暖暖的眼淚跟寒雨混成一塊
[03:06.39]眼前的色彩忽然被掩蓋
[03:10.31]你的影子無(wú)情在身邊徘徊
[03:14.23]你就像一個(gè)劊子手把我出賣
[03:18.34]我的心彷佛被剌刀狠狠地宰
[03:22.33]在懸崖上的愛(ài) 誰(shuí)會(huì)愿意接受最痛的意外
[03:28.66]
[03:34.57]冷冷的冰雨在臉上胡亂的拍
[03:38.33]暖暖的眼淚跟寒雨混成一塊
[03:42.31]眼前的色彩忽然被掩蓋
[03:46.32]你的影子無(wú)情在身邊徘徊
[03:50.27]你就像一個(gè)劊子手把我出賣
[03:54.34]我的心彷佛被剌刀狠狠地宰
[03:58.34]懸崖上的愛(ài) 誰(shuí)會(huì)敢去采
[04:02.37]還是愿意接受最痛的意外 最愛(ài)的女孩
[04:08.85]
[04:19.72]懸崖上的愛(ài) 誰(shuí)會(huì)敢去采
[04:31.84]還是愿意接受最痛的意外 最愛(ài)的女孩
[04:51.75]
[05:10.60]歌手獨(dú)白
[06:16.76]```

解析lrc歌詞

這可能是最常見(jiàn)的格式了,每行為一句歌詞碘橘,[]括號(hào)內(nèi)為歌詞對(duì)應(yīng)的時(shí)間區(qū)間互订,所以我們首先要做的事情就是將他們提取分離出來(lái),分別作為時(shí)間參數(shù)數(shù)組和歌詞內(nèi)容數(shù)組痘拆。這里我參考了一些博客的方法仰禽,解析lrc文件的代碼如下:

#import <Foundation/Foundation.h> @interface LrcParser : NSObject //時(shí)間 @property (nonatomic,strong) NSMutableArray *timerArray; //歌詞 @property (nonatomic,strong) NSMutableArray *wordArray; //解析歌詞 -(void) parseLrc; //解析歌詞 -(void) parseLrc:(NSString*)lrc; @end

實(shí)現(xiàn)代碼

@implementation LrcParser -(instancetype) init{ self=[super init]; if(self!=nil){ self.timerArray=[[NSMutableArray alloc] init]; self.wordArray=[[NSMutableArray alloc] init]; } return self; }

-(NSString *)getLrcFile:(NSString *)lrc{ NSString* filePath=[[NSBundle mainBundle] pathForResource:lrc ofType:@"lrc"]; return [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; }

//測(cè)試示例 -(void)parseLrc{ [self parseLrc:[self getLrcFile:@"冰雨"]]; }
-(void)parseLrc:(NSString *)lrc{ NSLog(@"%@",lrc); if(![lrc isEqual:nil]){ NSArray *sepArray=[lrc componentsSeparatedByString:@"["]; NSArray *lineArray=[[NSArray alloc] init]; for(int i=0;i<sepArray.count;i++){ if([sepArray[i] length]>0){ lineArray=[sepArray[i] componentsSeparatedByString:@"]"]; if(![lineArray[0] isEqualToString:@"\n"]){ [self.timerArray addObject:lineArray[0]];
[self.wordArray addObject:lineArray.count>1?lineArray[1]:@""]; } } } } } @end

經(jīng)過(guò)測(cè)試,可以將歌詞順利解析出來(lái)纺蛆,下面我們要將獲得歌詞數(shù)據(jù)應(yīng)用于控制器吐葵。

實(shí)現(xiàn)動(dòng)態(tài)歌詞頁(yè)面

看了QQ音樂(lè)的滾動(dòng)歌詞頁(yè)面后,可以知道是借助UITableView或者UIScrollView來(lái)實(shí)現(xiàn)的桥氏,這里我們采用UITableView來(lái)實(shí)現(xiàn)動(dòng)態(tài)歌詞界面温峭。

- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. //歌詞TableView代理 self.lrcTable.delegate=self; self.lrcTable.dataSource=self; //解析歌詞 self.lrcContent=[[LrcParser alloc] init]; [self.lrcContent parseLrc]; [self.lrcTable reloadData]; //初始化播放器 [self initPlayer]; //監(jiān)聽(tīng)播放器狀態(tài) [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateTime) userInfo:nil repeats:YES]; //載入歌詞背景 UIImage *img=[UIImage imageNamed:@"wall1.jpg"]; UIImageView *bgView=[[UIImageView alloc] initWithImage:[self getBlurredImage:img]]; self.lrcTable.backgroundView=bgView; } //cell委托 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ UITableViewCell *cell=[self.lrcTable dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; cell.textLabel.text=self.lrcContent.wordArray[indexPath.row]; if(indexPath.row==_currentRow) cell.textLabel.textColor = [UIColor redColor]; else cell.textLabel.textColor = [UIColor whiteColor]; cell.textLabel.textAlignment = NSTextAlignmentCenter; cell.textLabel.font = [UIFont systemFontOfSize:15]; cell.backgroundColor=[UIColor clearColor]; return cell; }

這里歌詞列表的背景我采用了高斯模糊的圖片,高斯模糊的方法如下:

//實(shí)現(xiàn)高斯模糊 -(UIImage *)getBlurredImage:(UIImage *)image{ CIContext *context = [CIContext contextWithOptions:nil]; CIImage *ciImage=[CIImage imageWithCGImage:image.CGImage]; CIFilter *filter=[CIFilter filterWithName:@"CIGaussianBlur"]; [filter setValue:ciImage forKey:kCIInputImageKey]; [filter setValue:@5.0f forKey:@"inputRadius"]; CIImage *result=[filter valueForKey:kCIOutputImageKey]; CGImageRef ref=[context createCGImage:result fromRect:[result extent]]; return [UIImage imageWithCGImage:ref]; }

播放器則采用AVPlayer识颊,其定義和初始化設(shè)置如下:

@interface ViewController : UIViewController<UITableViewDataSource,UITableViewDelegate> @property (nonatomic,strong) AVAudioPlayer *player; @end

-(void) initPlayer{ AVAudioSession *session=[AVAudioSession sharedInstance]; [session setActive:YES error:nil]; [session setCategory:AVAudioSessionCategoryPlayback error:nil]; [[UIApplication sharedApplication] beginReceivingRemoteControlEvents]; self.player=[[AVAudioPlayer alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"冰雨" withExtension:@"mp3"] error:nil]; //單曲循環(huán) self.player.numberOfLoops=10; [self.player prepareToPlay]; [self.player play]; }

這樣就為應(yīng)用定義了一個(gè)音樂(lè)播放器诚镰,下面要監(jiān)聽(tīng)播放器的時(shí)間參數(shù)奕坟,來(lái)載入對(duì)應(yīng)的歌詞祥款,如下:

[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateTime) userInfo:nil repeats:YES];

根據(jù)時(shí)間更新UI

-(void) updateTime{ CGFloat currentTime=self.player.currentTime; NSLog(@"%d:%d",(int)currentTime / 60, (int)currentTime % 60); for (int i=0; i<self.lrcContent.timerArray.count; i++) { NSArray *timeArray=[self.lrcContent.timerArray[i] componentsSeparatedByString:@":"]; float lrcTime=[timeArray[0] intValue]*60+[timeArray[1] floatValue]; if(currentTime>lrcTime){ _currentRow=i; }else break; } [self.lrcTable reloadData]; [self.lrcTable scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:_currentRow inSection:0] atScrollPosition:UITableViewScrollPositionMiddle animated:YES]; }

最后編譯運(yùn)行,就會(huì)發(fā)現(xiàn)一個(gè)滾動(dòng)歌詞播放器就實(shí)現(xiàn)啦月杉。
完整Demo項(xiàng)目地址:https://github.com/ChangweiZhang/AudioPlayerDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刃跛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子苛萎,更是在濱河造成了極大的恐慌桨昙,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腌歉,死亡現(xiàn)場(chǎng)離奇詭異蛙酪,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)翘盖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門桂塞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人馍驯,你說(shuō)我怎么就攤上這事阁危。” “怎么了汰瘫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵狂打,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我混弥,道長(zhǎng)趴乡,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮晾捏,結(jié)果婚禮上官辽,老公的妹妹穿的比我還像新娘。我一直安慰自己粟瞬,他們只是感情好同仆,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著裙品,像睡著了一般俗批。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上市怎,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天岁忘,我揣著相機(jī)與錄音,去河邊找鬼区匠。 笑死干像,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的驰弄。 我是一名探鬼主播麻汰,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼戚篙!你這毒婦竟也來(lái)了五鲫?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤岔擂,失蹤者是張志新(化名)和其女友劉穎位喂,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體乱灵,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡塑崖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了痛倚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片规婆。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖状原,靈堂內(nèi)的尸體忽然破棺而出聋呢,到底是詐尸還是另有隱情,我是刑警寧澤颠区,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布削锰,位于F島的核電站,受9級(jí)特大地震影響毕莱,放射性物質(zhì)發(fā)生泄漏器贩。R本人自食惡果不足惜颅夺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蛹稍。 院中可真熱鬧吧黄,春花似錦、人聲如沸唆姐。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)奉芦。三九已至赵抢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間声功,已是汗流浹背烦却。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留先巴,地道東北人其爵。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像伸蚯,于是被迫代替她去往敵國(guó)和親摩渺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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