最近朋友想作個音樂App,讓我幫忙參考下。其中歌詞動態滾動的效果,正好我以前也沒作過,順便學習一下,先來個預覽效果。git
實現思路github
歌詞常見的就是lrc歌詞了,咱們這裏也是經過解析lrc歌詞文件來獲取其播放參數,以實現和播放器協同。下面是我從百度音樂獲取的歌詞文件示例:數組
[ti:冰雨] [ar:劉德華] [al:笨小孩] [00:0.05]冰雨 [00:0.94]做詞:劉德華、李密 做曲:潘協慶 [00:01.23]演唱:劉德華 [00:01.37] [00:04.79](歌手獨白) [00:17.18]我是在等待 一個女孩 [00:25.18]仍是在等待沉淪苦海 [00:32.91]一我的靜靜發呆 沒有人去管花謝花開 [00:41.03]沒法確定的愛 左右搖擺 [00:45.43]只好把心酸往深內心塞 [00:49.61]我是在等待 你的回來 [00:57.73]難道只換回一句活該 [01:05.27]一我的靜靜發呆 [01:09.18]兩我的卻有不一樣無奈 [01:13.15]好好的一份愛 啊怎麼會慢慢變壞 [01:18.43] [01:20.44]冷冷的冰雨在臉上胡亂的拍 [01:24.31]暖暖的眼淚跟寒雨混成一塊 [01:28.32]眼前的色彩突然被掩蓋 [01:32.28]你的影子無情在身邊徘徊 [01:36.30]你就像一個劊子手把我出賣 [01:40.35]個人心似乎被剌刀狠狠地宰 [01:44.36]在懸崖上的愛 誰會願意接受最痛的意外 [01:51.09] [02:26.59]我是在等待你的回來 [02:35.52]難道只換回一句活該 [02:42.99]一我的靜靜發呆 [02:46.99]兩我的卻有不一樣無奈 [02:51.08]好好的一份愛 啊怎麼會慢慢變壞 [02:56.42] [02:58.54]冷冷的冰雨在臉上胡亂的拍 [03:02.41]暖暖的眼淚跟寒雨混成一塊 [03:06.39]眼前的色彩突然被掩蓋 [03:10.31]你的影子無情在身邊徘徊 [03:14.23]你就像一個劊子手把我出賣 [03:18.34]個人心似乎被剌刀狠狠地宰 [03:22.33]在懸崖上的愛 誰會願意接受最痛的意外 [03:28.66] [03:34.57]冷冷的冰雨在臉上胡亂的拍 [03:38.33]暖暖的眼淚跟寒雨混成一塊 [03:42.31]眼前的色彩突然被掩蓋 [03:46.32]你的影子無情在身邊徘徊 [03:50.27]你就像一個劊子手把我出賣 [03:54.34]個人心似乎被剌刀狠狠地宰 [03:58.34]懸崖上的愛 誰會敢去採 [04:02.37]仍是願意接受最痛的意外 最愛的女孩 [04:08.85] [04:19.72]懸崖上的愛 誰會敢去採 [04:31.84]仍是願意接受最痛的意外 最愛的女孩 [04:51.75] [05:10.60]歌手獨白 [06:16.76]
解析lrc歌詞session
這多是最多見的格式了,每行爲一句歌詞,[]括號內爲歌詞對應的時間區間,因此咱們首先要作的事情就是將他們提取分離出來,分別做爲時間參數數組和歌詞內容數組。這裏我參考了一些博客的方法,解析lrc文件的代碼以下:oop
#import <Foundation/Foundation.h> @interface LrcParser : NSObject //時間 @property (nonatomic,strong) NSMutableArray *timerArray; //歌詞 @property (nonatomic,strong) NSMutableArray *wordArray; //解析歌詞 -(void) parseLrc; //解析歌詞 -(void) parseLrc:(NSString*)lrc; @end
實現代碼學習
@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]; } //測試示例 -(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
通過測試,能夠將歌詞順利解析出來,下面咱們要將得到歌詞數據應用於控制器。測試
實現動態歌詞頁面atom
看了QQ音樂的滾動歌詞頁面後,能夠知道是藉助UITableView或者UIScrollView來實現的,這裏咱們採用UITableView來實現動態歌詞界面。spa
- (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]; //監聽播放器狀態 [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; }
這裏歌詞列表的背景我採用了高斯模糊的圖片,高斯模糊的方法以下:代理
//實現高斯模糊 -(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,其定義和初始化設置以下:
@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]; //單曲循環 self.player.numberOfLoops=10; [self.player prepareToPlay]; [self.player play]; }
這樣就爲應用定義了一個音樂播放器,下面要監聽播放器的時間參數,來載入對應的歌詞,以下:
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(updateTime) userInfo:nil repeats:YES];
根據時間更新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]; }
最後編譯運行,就會發現一個滾動歌詞播放器就實現啦。