iOS開發手記-仿QQ音樂播放器動態歌詞的實現

最近朋友想作個音樂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];
}

 

最後編譯運行,就會發現一個滾動歌詞播放器就實現啦。

完整Demo項目地址:https://github.com/ChangweiZhang/AudioPlayerDemo

相關文章
相關標籤/搜索