zoukankan      html  css  js  c++  java
  • iOS开发手记-仿QQ音乐播放器动态歌词的实现

    最近朋友想做个音乐App,让我帮忙参考下。其中歌词动态滚动的效果,正好我之前也没做过,顺便学习一下,先来个预览效果。

    实现思路

    歌词常见的就是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歌词

    这可能是最常见的格式了,每行为一句歌词,[]括号内为歌词对应的时间区间,所以我们首先要做的事情就是将他们提取分离出来,分别作为时间参数数组和歌词内容数组。这里我参考了一些博客的方法,解析lrc文件的代码如下:

    #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:@"
    "]){
                        [self.timerArray addObject:lineArray[0]];
                        
                        [self.wordArray addObject:lineArray.count>1?lineArray[1]:@""];
                    }
                }
            }
        }
    }
    @end

    经过测试,可以将歌词顺利解析出来,下面我们要将获得歌词数据应用于控制器。

    实现动态歌词页面

    看了QQ音乐的滚动歌词页面后,可以知道是借助UITableView或者UIScrollView来实现的,这里我们采用UITableView来实现动态歌词界面。

    - (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

  • 相关阅读:
    第二阶段冲刺第六天
    梦断代码阅读笔记三
    第二阶段冲刺第五天
    第二阶段冲刺第四天
    第二阶段冲刺第三天
    第二阶段冲刺第二天
    软件工程第十四周总结
    第二阶段冲刺第一天
    第一阶段冲刺意见评论
    软件工程第十三周总结
  • 原文地址:https://www.cnblogs.com/mantgh/p/5208034.html
Copyright © 2011-2022 走看看