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}

2016-06-27
16: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,千万别用你喜欢的歌曲去做,不然那首歌就被你毁

了,各位有兴趣的去github下载下听听,有Bug记得告诉我哟,Love Story确实很好听,

但是被我听吐了。。

Demo地址:https://github.com/DeftMKJ/MusicDemo

不早啦,再听一遍就睡了,各位晚安

时间: 2024-11-06 18:08:22

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

ios 简单的本地音乐播放器

一.导入资源文件 二.新建一个控制器,继承于UITableViewController,用来展示播放列表 1.播放列表的实现 @interface MusicListViewController (){ //定义一个播放列表数组 NSMutableArray *musicList; } - (void)viewDidLoad { [super viewDidLoad]; //调用解析文件类方法,得到播放列表 musicList=[MusicModel allMusics]; } - (NSInt

【源码分享】mui实现简单的手机音乐播放器

mui实现简单的手机音乐播放器 最近先来无事,我用mui写了一个可以跨页面控制的音乐播放器.主要功能有上一曲,下一曲,播放,暂停,感兴趣的可以继续看下去. 说的总是不实在,直接上源码,有兴趣的可以读下注释. 1首页代码 ①首页的html代码 1 <a> 2 <i id="bofang" class="iconfont icon-play-o"></i> <!--就是一个播放按钮没啥特殊的--> 3 </a>

ios开发:一个音乐播放器的设计与实现

github地址:https://github.com/wzpziyi1/MusicPlauer 这个medo,关于歌曲播放的主要功能都实现了的.下一曲.上一曲,暂停,根据歌曲的播放进度动态滚动歌词,将当前正在播放的歌词放大显示,拖动进度条,歌曲跟着变化,并且使用Time Profiler进行了优化,还使用XCTest对几个主要的类进行了单元测试. 已经经过真机调试,在真机上可以后台播放音乐,并且锁屏时,显示一些主要的歌曲信息. 首页: 歌曲内部播放: 当拖动小的进度条的时候,歌曲也会随之变化.

简单的HTML5音乐播放器(带歌词滚动)

首先需要整理好lrc格式的歌词放到script标签中以供程序处理.然后把音乐链接放到audio的src属性里就可以了. 源码: HTML部分 1 <div class="container"> 2 <audio id="player" src="test.mp3" loop controls preload></audio> 3 <div id="lrcArea"></di

用Vue来实现音乐播放器(九):歌单数据接口分析

z这里如果我们和之前获取轮播图的数据一样来获取表单的数据  发现根本获取不到 原因是qq音乐在请求头里面加了authority和refer等 但是如果我们通过jsonp实现跨域来请求数据的话  是根本不能够修改请求头的  所以我们就考虑用axios  但是axios又不能进行跨域  那么我们要怎么拿到qq音乐的服务器的数据呢??其实是有办法解决的:我们可以进行后端接口代理  那么什么是后端代理呢?? 如果要使用axios直接进行跨域访问是不可以的,这是就需要配置代理了,为什么要配置代理呢? 原因

Simple2D-14(音乐播放器)简介

接下来文章中,会介绍一个简单的程序--音乐播放器.通过编写一个音乐播放器在 Simple2D 中加入两个库:音频库 bass 和界面库 ImGui. 下面是音乐播放器的预览图: 播放器的功能比较简单,音频播放使用了 bass 库,界面则是使用 ImGui 库.

逗逼音乐播放器制作日志(一)&lt;附源码&gt;

我很喜欢编程,喜欢看到一个项目,从最初的几行代码慢慢变成好几个类,几千行代码.回头看看,这都是一个字母一个词语打出来的.就会觉得很开心... 曾经去报读过专业课程.可惜课程完毕后无缘成为一名码农,心里很是遗憾...现在记着的也不多了,不想就此放弃..于是决定制作一个简单的本地音乐播放器吧...之前已经写了点,网上参考了很多资料.希望各位大牛,多多指点...现在算是完成了3/1吧...我只能算是个半吊子,写不出什么精彩的代码.. 非常可惜的是,我在写的时候没有将Service加入,导致现在只能前台

实践--音乐播放器

话不多说,先上效果图 这里由于模拟器的适配不太好,一些显示的细节并不如意,在我的手机上就都能实现功能 比如我每次打开软件是一张图片,后台执行筛选音乐文件,模拟器上却不显示图片 我每次放歌都有个Notification告诉我在放哪一首,然后消失,模拟器上却也不不显示 基本细节就是这些吧,这个软件运行在手机上效果更理想一些. 基本思路 音乐播放器其实就是应用了Activity,Service和BroadcaReceiver这三个组件,再配合MediaPlayer的使用,完成各种逻辑的设计,就可以实现

iOS 简单音乐播放器 界面搭建

如图搭建一个音乐播放器界面,具备以下几个简单功能: 1,界面协调,整洁. 2,点击播放,控制进度条. 3.三收藏歌曲,点击收藏,心形收藏标志颜色加深. 4,左右按钮,切换歌曲图片和标题. 5,点击中间图片,隐藏所有按钮,仅显示蓝色背景. 设计的整体思路: 1.在搭建界面的时候,为了整洁和方便后续的功能的添加,需要将整个的界面划分为几个部分: ①:最上面的一行包括:一个返回按钮.一个歌曲名称.一个收藏按钮: ②:第二行:一个slider控件.两侧是当前的歌曲播放进度和歌曲的总时长--两个lable