失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > iOS 简单实用的音乐播放器 少年 自己做个歌单吧。。。。。。

iOS 简单实用的音乐播放器 少年 自己做个歌单吧。。。。。。

时间:2020-06-09 12:59:56

相关推荐

iOS 简单实用的音乐播放器 少年 自己做个歌单吧。。。。。。

我也不知道为什么突然会想写一下音乐播放器的,感觉应该挺好的玩,自己把自己喜欢的歌曲导出来,用程序加载跑起来,那歌听起来必定很带感啊。。。。。。不过那首Love Story被我听了无数遍。。。。。。听吐了

各位看官有兴趣也可以听听。其实前期准备是很坑爹的,找歌词真的蛋疼啊

废话不多说,老规矩,看成品先:

首先

做个播放器的界面出来,上面是个tableView来加载歌词,底部两个Slider,一个声音,一个进度,最底下三个Button。

这里简单介绍下用AutoLayout实现底部三个Button等宽,等间距的需求实现//底部三个按钮平分屏幕的宽度做法// 1.首先固定左侧第一个按钮的下和左的约束固定好,其中高度可以给也可以不给,让文字自动填充// 2.然后选中三个按钮,选中垂直对齐以及等宽的两个必要条件// 3.之后中间的按钮只要设置距离左侧按钮的约束就好// 4.最后让最右侧的按钮距离右边的约束,左侧的约束固定好,选中三个,按下option + command + =,对齐即可

然后

导入需要操作的歌曲和歌词进行路径存储

控件

#import "ViewController.h"#import <AVFoundation/AVFoundation.h>#import "MKJParserLrc.h"#import "UIImage+ImageEffects.h"@interface ViewController () <UITableViewDataSource,UITableViewDelegate,AVAudioPlayerDelegate>@property (weak, nonatomic) IBOutlet UITableView *tableView;@property (weak, nonatomic) IBOutlet UISlider *volSlider;@property (weak, nonatomic) IBOutlet UISlider *progressSlider;@property (nonatomic,strong) AVAudioPlayer *audioPlayer; // AVAudioPlayer ----> 音频 本地@property (nonatomic,strong) NSArray *mp3Arr; // mp3路径@property (nonatomic,strong) NSArray *lrcArr; // 歌词路径@property (nonatomic,assign) NSInteger mp3Index; // 当前的播放下表@property (nonatomic,assign) NSUInteger currentRow; // 当前哪一行@property (nonatomic,strong) MKJParserLrc *mkj; // 解析歌词用的@end

这里我的图片我做了简单的高斯模糊,这里介绍个类给大家,一并把代码都给出来,需要的拿去用把

- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.self.view.backgroundColor = [UIColor colorWithRed:193/255.4 green:193/255.0 blue:193/255.4 alpha:0.7];[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;self.tableView.rowHeight = 60;// 图片高斯模糊UIImage *image = [UIImage imageNamed:@"436c1b64a2b6a4cbab09ee22db3851f4-1400x2100.jpg"];image = [image applyBlurWithRadius:15 tintColor:nil saturationDeltaFactor:1.5 maskImage:nil];self.tableView.backgroundView = [[UIImageView alloc] initWithImage:image];// 存储路径self.mp3Arr = @[[[NSBundle mainBundle] pathForResource:@"Love Story" ofType:@"mp3"],[[NSBundle mainBundle] pathForResource:@"薛之谦-演员" ofType:@"mp3"],[[NSBundle mainBundle] pathForResource:@"华晨宇-异类" ofType:@"mp3"]];self.lrcArr = @[[[NSBundle mainBundle] pathForResource:@"Love Story" ofType:@"lrc"],[[NSBundle mainBundle] pathForResource:@"薛之谦-演员" ofType:@"lrc"],[[NSBundle mainBundle] pathForResource:@"华晨宇-异类" ofType:@"lrc"]];self.mkj = [[MKJParserLrc alloc] init];// 根据路径加载歌曲和歌词[self loadMp3:self.mp3Arr[self.mp3Index] lrcPath:self.lrcArr[self.mp3Index]];// 启动定时器,一直更新[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(changeTime:) userInfo:nil repeats:YES];}

之后

我们加载MP3歌曲以及解析歌词

#import <AVFoundation/AVFoundation.h>导入这个头文件,用AVAudioPlayer来进行播放// 加载歌词和歌曲- (void)loadMp3:(NSString *)mp3Str lrcPath:(NSString *)lrcStr{// 这个方法是获取网上的// self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL URLWithString:mp3Str] error:nil];// 下面的是本地的self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:mp3Str] error:nil];self.audioPlayer.delegate = self;self.audioPlayer.volume = 0.5f;// 解析歌词方法[self.mkj parserLrcWithFileURL:lrcStr];// 让slider的进去和歌曲最大时间一致self.progressSlider.maximumValue = self.audioPlayer.duration;// 准备播放[self.audioPlayer prepareToPlay];}

用自己创建的对象进行歌词解析,暴露个方法传本地URL进来

@interface MKJParserLrc : NSObject@property (nonatomic,strong) NSMutableArray *timeArr;@property (nonatomic,strong) NSMutableArray *lrcArr;- (void)parserLrcWithFileURL:(NSString *)lrcPath;@end

这里分割字符串的方法千千万,咱只是展示一种

- (void)parserLrcWithFileURL:(NSString *)lrcPath{// 每次进来都清除掉之前的[self.lrcArr removeAllObjects];[self.timeArr removeAllObjects];// 通过路径读取歌词的字符串NSString *lrcStr = [NSString stringWithContentsOfFile:lrcPath encoding:NSUTF8StringEncoding error:nil];// 分割NSArray *lrcArr = [lrcStr componentsSeparatedByString:@"["];// 继续分割for (NSString *sepStr in lrcArr) {// 无脑分割NSArray *sepArr = [sepStr componentsSeparatedByString:@"]"];// 三种可能不要,第一种就是头部歌词,第二个时间中没有歌词的,第三个就是没有歌词换行的if (!([sepArr[0] isEqualToString:@""] || [sepArr[1] isEqualToString:@"\n"] || [sepArr[1] isEqualToString:@"\r\n"])) {[self.timeArr addObject:sepArr[0]];[self.lrcArr addObject:sepArr[1]];}}}

第四步

把点击事件和代理方法实现

// 上一首- (IBAction)previousSong:(id)sender{[self.audioPlayer stop];self.mp3Index--;if (_mp3Index==-1) {self.mp3Index = 2;}[self loadMp3:self.mp3Arr[self.mp3Index] lrcPath:self.lrcArr[self.mp3Index]];[self.audioPlayer play];}// 播放或者暂停- (IBAction)play:(id)sender {if (self.audioPlayer.playing) {[self.audioPlayer pause];}else{[self.audioPlayer play];}}// 下一首- (IBAction)NextSong:(id)sender{[self.audioPlayer stop];self.mp3Index++;if (self.mp3Index == 3) {self.mp3Index = 0;}[self loadMp3:self.mp3Arr[self.mp3Index] lrcPath:self.lrcArr[self.mp3Index]];[self.audioPlayer play];}// 声音change- (IBAction)volChange:(UISlider *)sender {self.audioPlayer.volume = sender.value;}// 进度change- (IBAction)rateChange:(UISlider *)sender {self.audioPlayer.currentTime = sender.value;}- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{[self NextSong:nil];}

最后启动个定时器,让进度条和歌词实时更新,让歌词和歌曲匹配,这个方法也是最关键

// 更新的方法- (void)changeTime:(NSTimer *)timer{// 让进度条和当前播放时间一直self.progressSlider.value = self.audioPlayer.currentTime;// 遍历歌词,来记录当前是播放哪个row[self.mkj.timeArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {NSString *timeStr = self.mkj.timeArr[idx];NSArray *timeArr = [timeStr componentsSeparatedByString:@":"];CGFloat seconds = [timeArr[0] floatValue] * 60 + [timeArr[1] floatValue];if (seconds >= self.audioPlayer.currentTime) {if (idx == 0){self.currentRow = idx;}else{self.currentRow = idx - 1;}*stop = YES;}}];// 刷新[self.tableView reloadData];// 滚动到指定的row现实歌词if (self.currentRow < self.mkj.lrcArr.count) {[self.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:self.currentRow inSection:0] atScrollPosition:UITableViewScrollPositionMiddle animated:YES];}}

天真的我以为这就完了,这破东西能让你崩的措手不及!!!

(lldb) po indexPath<NSIndexPath: 0xc000000007a00016> {length = 2, path =0 - 61}-06-2716:22:47.557 MusicPlayerDemo[5176:272368] *** Terminating app due to uncaught exception 'NSRangeException', reason:'*** -[__NSArrayM objectAtIndex:]: index 61 beyond bounds [0 .. 51]'*** First throw call stack:

这就很好理解了,首先这三首歌的歌词分别52 46 81行,当我们快速滑动进度条的时候,

再切换到上一首或者下一首,数组越界了啊,歌词不同,肯定会越界,找到原因就好办了

在加载CELL的方法里面加上这个判断就妥妥的了,你想怎么搞都不会蹦了

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];if (indexPath.row < self.mkj.lrcArr.count) {cell.textLabel.text = self.mkj.lrcArr[indexPath.row];}

Demo地址:/DeftMKJ/MusicDemo

如果觉得《iOS 简单实用的音乐播放器 少年 自己做个歌单吧。。。。。。》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。