iOS 模仿QQ音乐用Xcode写的一个播放器

**
我使用AvPlayer写的,所以大家一定得记住要导入AvFoundation的库,话不多说,直接上代码 **
这里我是把AvPlayer封装到了一个类里,

// //CXPlayMvViewController.m //LeeMusic // //Created by ChuXiang on 15/12/9. //Copyright ? 2015年 ChuXiang. All rights reserved. //#import "LoveMusicPlayer.h" #import @implementation LoveMusicPlayer+ (LoveMusicPlayer *)sharePlayer{ static LoveMusicPlayer* Player = nil; if (Player==nil) { Player =[[LoveMusicPlayer alloc] init]; } return Player; }- (void)playWithURL:(NSString *)url{ AVPlayerItem * item = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:url]]; [self replaceCurrentItemWithPlayerItem: item]; [self play]; } @end

这里是在ViewController里完成的代码,我是直接找了一个音乐播放器的歌单的Url然后在这里请求数据的。
其实做起来也没那么难,AvPlayer它本身就有很多方法供大家使用,比如从url中获取歌曲总长(不过大家它给的时间是以秒为单位的,大家别忘了把它化成分秒,下面我也写到,大家可以参考),比如播放器音量,直接跟你写的音量slider绑定到一起等等。大家可以慢慢看,先把页面铺完(歌曲的图片转动我为了偷工减料就直接用计时器写了,看起来有点Low),再把该完成的方法写了就完事了。
// //ViewController.m //PlayMusic // //Created by ChuXiang on 16/1/3. //Copyright ? 2016年 ChuXiang. All rights reserved. //#import "ViewController.h" #import "LoveMusicPlayer.h" #import "CXSingListModel.h" #import #import "UIImageView+WebCache.h" #import "CXNetWorkTool.h" #define kWidth ([UIScreen mainScreen].bounds.size.width / 375) #define kHeight ([UIScreen mainScreen].bounds.size.height / 667) #define kControlBarHeight 300 #define kControlBarCenterY (kScreenHeight - 150)#define kScreenWidth [UIScreen mainScreen].bounds.size.width#define kScreenHeight [UIScreen mainScreen].bounds.size.height#define kControlBarOriginY (kScreenHeight - kControlBarHeight)#define kMusicInfoOriginY (kControlBarOriginY + 40)#define kControlBarCenterX self.view.center.x #define kControlBarCenterY (kScreenHeight - 150) #define kButtonOffsetX 120 #define kFindMusicGetURL @"http://a.vip.migu.cn/rdp2/v5.5/index.do?ua=Iphone_Sst&version=4.2421&pageno=1"@interface ViewController () //处理音乐数据 @property (nonatomic, copy) NSString *songId; @property (nonatomic, retain) NSMutableArray *myArr; @property (nonatomic, assign) NSInteger index; @property (nonatomic, strong)CXSingListModel *model; // 播放器 @property (nonatomic, retain) LoveMusicPlayer *player; @property (nonatomic, assign) BOOL isPlaying; //播放列表属性 @property (nonatomic, retain) UIImageView *myImageView; @property (nonatomic, retain) UIButton *playButton; @property (nonatomic, retain) UILabel *authorSongLabel; @property (nonatomic, retain) UILabel *songNameLabel; @property (nonatomic, retain) UISlider *slider; @property (nonatomic, retain) NSTimer *timer; @property (nonatomic, retain) NSTimer *imgTimer; @property (nonatomic, retain) UIImageView *backImage; @property (nonatomic, retain) UILabel *timeLable; @property (nonatomic, retain) UILabel *currentTimeLable; @property (nonatomic, retain) UIScrollView *scrollView; @property (nonatomic, retain) UIPageControl *pageControl; @property (nonatomic, retain) UISlider *volumeSlider; //判断播放状态 @property (nonatomic, assign) NSInteger type; //播放状态的枚举 typedef NS_ENUM(NSUInteger, PlayType) { PlayTypeLive = 0, PlayTypeNext, PlayTypeLast }; @end@implementation ViewControllerstatic ViewController *single = nil; // 单例执行 只初始化一次 + (instancetype) shareSingleViewController {static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ //在多线程中保证只初始化一次 single = [[ViewController alloc] init]; }); return single; }//网络请求数据 - (void)getWithUrl:(NSString *)url parameter:(NSDictionary *)parameter withKey:(NSString *)key WithValue:(NSString *)value{ self.myArr = [NSMutableArray arrayWithCapacity:0]; [CXNetWorkTool getWithUrl:url parameter:nil httpHeader:nil responseType:ResponseTypeJSON success:^(id result) { if (result) { NSDictionary *dic = result; NSArray *array = dic[@"groups"]; NSDictionary *dic1 = array[3]; NSArray *array1 = dic1[@"songs"]; for (NSDictionary *dic in array1) { CXSingListModel *model = [[CXSingListModel alloc] initWithDictionary:dic]; [self.myArr addObject:model]; } dispatch_async(dispatch_get_main_queue(), ^{ [self createMusicData]; }); } } fail:^(NSError *error) { //NSLog(@"%@", error); }]; }- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. [self getWithUrl:kFindMusicGetURL parameter:nil withKey:nil WithValue:nil]; self.view.backgroundColor = [UIColor whiteColor]; //播放背景图片 self.backImage = [[UIImageView alloc] initWithFrame:self.view.frame]; //上部分高亮显示 UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight]; UIVisualEffectView *effectview = [[UIVisualEffectView alloc] initWithEffect:blur]; effectview.frame = CGRectMake(0, 0, self.backImage.frame.size.width , self.backImage.frame.size.height); [self.backImage addSubview:effectview]; [self.view addSubview:self.backImage]; //pageControl CGFloat size_width = CGRectGetWidth(self.view.bounds) - 80; self.pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 60 + size_width, kScreenWidth, 20)]; self.pageControl.numberOfPages = 2; self.pageControl.currentPage = 0; //createSrollView self.scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.bounds), CGRectGetHeight(self.view.bounds) - 250)]; self.scrollView.delegate = self; self.scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.scrollView.bounds) * 2, CGRectGetHeight(self.scrollView.bounds)); self.scrollView.pagingEnabled = YES; self.scrollView.showsHorizontalScrollIndicator = NO; [self.view addSubview:self.scrollView]; [self.view addSubview:self.pageControl]; //底部播放界面 blur效果 UIVisualEffectView *background = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffect effectWithStyle:UIBlurEffectStyleExtraLight]]; background.frame = CGRectMake(0, kControlBarOriginY + 50, kScreenWidth, kControlBarHeight); [self.view addSubview:background]; //进入之后自动播放 self.isPlaying = YES; //创建音乐播放器对象 self.player = [LoveMusicPlayer sharePlayer]; // 添加播放完成的通知 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:AVPlayerItemDidPlayToEndTimeNotification object:self.player.currentItem]; //滚动的歌曲图片 self.myImageView = [[UIImageView alloc] initWithFrame:CGRectMake(40, 50, size_width, size_width)]; self.myImageView.layer.cornerRadius = size_width / 2; self.myImageView.layer.borderColor = [UIColor lightGrayColor].CGColor; self.myImageView.layer.borderWidth = 2; self.myImageView.layer.masksToBounds = YES; [self.scrollView addSubview:self.myImageView]; //歌手名 self.authorSongLabel = [[UILabel alloc] initWithFrame:CGRectMake( 0 , kScreenHeight - 230, kScreenWidth, 30)]; //居中对齐 self.authorSongLabel.textAlignment = NSTextAlignmentCenter; [self.view addSubview:self.authorSongLabel]; //歌手label self.songNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.authorSongLabel.frame.origin.y + self.authorSongLabel.frame.size.height + 10, kScreenWidth, 20)]; self.songNameLabel.textAlignment = NSTextAlignmentCenter; self.songNameLabel.font = [UIFont systemFontOfSize:11]; [self.view addSubview:self.songNameLabel]; // 进度条 self.slider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth - 100, 20)]; self.slider.center = CGPointMake(kControlBarCenterX, kControlBarCenterY + 10); [self.slider setThumbImage:[UIImage imageNamed:@"volumn_slider_thumb"] forState:UIControlStateNormal]; self.slider.minimumTrackTintColor = [UIColor blackColor]; self.slider.minimumValue = https://www.it610.com/article/0.0; self.slider.maximumValue = 1.0; [self.slider addTarget:self action:@selector(progressAction:) forControlEvents:UIControlEventValueChanged]; [self.view addSubview:self.slider]; //声音slider self.volumeSlider = [[UISlider alloc] initWithFrame:CGRectMake(0, 0, kScreenWidth - 100, 20)]; self.volumeSlider.center = CGPointMake(kControlBarCenterX, kControlBarCenterY + 60); [self.volumeSlider setThumbImage:[UIImage imageNamed:@"volumn_slider_thumb"] forState:UIControlStateNormal]; self.volumeSlider.maximumValue = https://www.it610.com/article/1; self.volumeSlider.minimumValueImage = [UIImage imageNamed:@"volumelow"]; self.volumeSlider.maximumValueImage = [UIImage imageNamed:@"volumehigh"]; self.volumeSlider.value = https://www.it610.com/article/1; self.volumeSlider.minimumTrackTintColor = [UIColor blackColor]; [self.volumeSlider addTarget:self action:@selector(handleVolumeAction:) forControlEvents:UIControlEventValueChanged]; [self.view addSubview:self.volumeSlider]; //当前播放时间label self.currentTimeLable = [[UILabel alloc] initWithFrame:CGRectMake(self.slider.frame.origin.x - 5 - 38, self.slider.frame.origin.y, 50, 20)]; self.currentTimeLable.text = @"00:00"; self.currentTimeLable.font = [UIFont systemFontOfSize:13]; [self.view addSubview:self.currentTimeLable]; //总时间label self.timeLable = [[UILabel alloc] initWithFrame:CGRectMake(self.slider.frame.origin.x + self.slider.frame.size.width, self.slider.frame.origin.y, 50, 20)]; self.timeLable.font = [UIFont systemFontOfSize:13]; [self.view addSubview:self.timeLable]; self.timeLable.text = @"11:11"; // 计时器 控制播放 self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(playerAction) userInfo:nil repeats:YES]; //控制转动头像 self.imgTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(imgTransform) userInfo:nil repeats:YES]; // 播放的button self.playButton = [UIButton buttonWithType:UIButtonTypeSystem]; self.playButton.frame = CGRectMake(160 * kWidth, self.view.frame.size.height - 60, 50 * kWidth, 50 * kWidth); [self.playButton setBackgroundImage:[UIImage imageNamed:@"stop"] forState:UIControlStateNormal]; [self.playButton addTarget:self action:@selector(clickPlay:) forControlEvents:UIControlEventTouchUpInside]; self.playButton.tag = 520; [self.view addSubview:self.playButton]; //上一曲的button UIButton *buttonUp = [UIButton buttonWithType:UIButtonTypeSystem]; buttonUp.frame = CGRectMake(60 * kWidth, self.view.frame.size.height - 50, 30 * kWidth, 30 * kWidth); [buttonUp setBackgroundImage:[UIImage imageNamed:@"pause"] forState:UIControlStateNormal]; [buttonUp addTarget:self action:@selector(playUp:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:buttonUp]; //下一曲的button UIButton *buttonNext = [UIButton buttonWithType:UIButtonTypeSystem]; buttonNext.frame = CGRectMake(280 * kWidth, self.view.frame.size.height - 50, 30 * kWidth, 30 * kWidth); [buttonNext setBackgroundImage:[UIImage imageNamed:@"next"] forState:UIControlStateNormal]; [buttonNext addTarget:self action:@selector(playNext:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:buttonNext]; }#pragma mark - 声音 - (void)handleVolumeAction:(UISlider *)sender { [self.player setVolume:sender.value]; }#pragma mark - SroolerView结束滑动 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { NSUInteger index = scrollView.contentOffset.x / scrollView.bounds.size.width; self.pageControl.currentPage = index; }#pragma mark - 计时器方法 - 图片转动 - (void)imgTransform {self.myImageView.transform = CGAffineTransformRotate(self.myImageView.transform, 0.01); }#pragma mark - 播放计时器方法 -(void)playerAction{//当前时间 / 总时间 self.slider.value = https://www.it610.com/article/CMTimeGetSeconds(self.player.currentItem.currentTime) / CMTimeGetSeconds(self.player.currentItem.duration); //总共时间(右边显示) NSInteger totalTime = CMTimeGetSeconds(self.player.currentItem.duration); NSInteger minTime = totalTime / 60; NSInteger secondTime = totalTime % 60; NSString *timeStr = [NSString stringWithFormat:@"%02ld:%02ld", (long)minTime,(long)secondTime]; self.timeLable.text = timeStr; //当前播放时间(左边显示) NSInteger totalTime1 = CMTimeGetSeconds(self.player.currentItem.currentTime); NSInteger minTime1 = totalTime1 / 60; NSInteger secondTime1 = totalTime1 % 60; NSString *timeStr1 = [NSString stringWithFormat:@"%02ld:%02ld", (long)minTime1,(long)secondTime1]; self.currentTimeLable.text = timeStr1; //判断是否是最后一首歌曲,如果是最后一首歌,播放完之后自动变换播放按钮 if((self.index == self.myArr.count - 1) && (totalTime==totalTime1)){ [self.player pause]; [self.playButton setBackgroundImage:[UIImage imageNamed:@"songplay"] forState:UIControlStateNormal]; }}#pragma mark - 进度条方法 -(void)progressAction:(UISlider *)slider{float current = slider.value; float nextCurrent = current * CMTimeGetSeconds(self.player.currentItem.duration); [self.player seekToTime:CMTimeMakeWithSeconds(nextCurrent, 1.0)]; [self.player play]; //在暂停的时候,如果拉动进度条,播放按钮就变成播放图片 [self.playButton setBackgroundImage:[UIImage imageNamed:@"stop"] forState:UIControlStateNormal]; // 控制计时器的最大范围 self.timer.fireDate =[NSDate distantPast]; }//上一曲 #pragma mark - 播放设置 - (void)playUp:(UIButton *)button{ //先查找当前歌曲 //判断,如果是第一首歌就不做任何操作,如果不是第一首就把id赋值给解析数据 if (self.index != 0) { CXSingListModel *listMode = self.myArr[self.index - 1]; //CXSingListModel *listMode = self.musicArr[self.index - 1]; NSString *str = [listMode.url stringByAppendingString:@"&ua=Iphone_Sst&version=4.2421&netType=1&toneFlag=1"]; self.songId = str; _type = PlayTypeLast; //调用数据解析 [self createMusicData]; [self.playButton setBackgroundImage:[UIImage imageNamed:@"stop"] forState:UIControlStateNormal]; }else{ //当上一曲没有歌曲 弹出alert提示框 [self.player pause]; UIAlertController *mBoxView = [UIAlertController alertControllerWithTitle:@"嗨" message:@"上面还没有歌曲~" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { [self dismissViewControllerAnimated:YES completion:^{}]; }]; UIAlertAction *otherAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { [self dismissViewControllerAnimated:YES completion:^{}]; }]; [mBoxView addAction:cancelAction]; [mBoxView addAction:otherAction]; [self presentViewController:mBoxView animated:YES completion:nil]; [self.playButton setBackgroundImage:[UIImage imageNamed:@"songplay"] forState:UIControlStateNormal]; }}//下一曲 - (void)playNext:(UIButton *)button{ //先查找当前歌曲 //然后播放下一曲 //判断是否是最后一曲,如果不是就重新赋值 if (self.index != self.myArr.count - 1) { CXSingListModel *listMode = self.myArr[self.index + 1]; NSString *str = [listMode.url stringByAppendingString:@"&ua=Iphone_Sst&version=4.2421&netType=1&toneFlag=1"]; self.songId = str; _type = PlayTypeNext; [self createMusicData]; }else{ //当下一曲没有歌曲 弹出alert提示框 UIAlertController *mBoxView = [UIAlertController alertControllerWithTitle:@"嗨" message:@"已经最后一首了~" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { [self dismissViewControllerAnimated:YES completion:^{}]; }]; UIAlertAction *otherAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { [self dismissViewControllerAnimated:YES completion:^{}]; }]; [mBoxView addAction:cancelAction]; [mBoxView addAction:otherAction]; [self presentViewController:mBoxView animated:YES completion:nil]; [self.playButton setBackgroundImage:[UIImage imageNamed:@"songplay"] forState:UIControlStateNormal]; } }#pragma mark - 播放时界面赋值 - (void)createMusicData {//先查找当前歌曲 self.index = 0; for (NSInteger i = 0; i < self.myArr.count; i++) { CXSingListModel *detailMo = self.myArr[i]; NSString *str = [detailMo.url stringByAppendingString:@"&ua=Iphone_Sst&version=4.2421&netType=1&toneFlag=1"]; if ([str isEqualToString:self.songId]) { self.index = i; break; } } if (_type == PlayTypeLive) { CXSingListModel *model = self.myArr[self.index]; //判断传进来的歌曲id是否与正在播放的id是否相同,如果相同不执行,不相同执行换歌 if (![self.model.contentid isEqualToString:model.contentid]) { NSString *str = model.url; NSString *str1 = [str stringByAppendingString:@"&ua=Iphone_Sst&version=4.2421&netType=1&toneFlag=1"]; [self.player playWithURL:str1]; [self.backImage sd_setImageWithURL:[NSURL URLWithString:model.albumImg]]; if ([model.albumImg isEqualToString:@""]) { self.backImage.backgroundColor = [UIColor redColor]; }[self.myImageView sd_setImageWithURL:[NSURL URLWithString:model.albumImg]]; self.songNameLabel.text = [NSString stringWithFormat:@"%@ - %@", model.singer, model.album]; self.authorSongLabel.text = model.title; self.model = model; }}else if (_type == PlayTypeLast) { if (self.index > 0) { CXSingListModel *model = self.myArr[self.index - 1]; NSString *str = model.url; NSString *str1 = [str stringByAppendingString:@"&ua=Iphone_Sst&version=4.2421&netType=1&toneFlag=1"]; [self.player playWithURL:str1]; [self.backImage sd_setImageWithURL:[NSURL URLWithString:model.albumImg]]; [self.myImageView sd_setImageWithURL:[NSURL URLWithString:model.albumImg]]; self.songNameLabel.text = [NSString stringWithFormat:@"%@ - %@", model.singer, model.album]; self.authorSongLabel.text = model.title; }else { CXSingListModel *model = self.myArr[0]; NSString *str = model.url; NSString *str1 = [str stringByAppendingString:@"&ua=Iphone_Sst&version=4.2421&netType=1&toneFlag=1"]; [self.player playWithURL:str1]; [self.backImage sd_setImageWithURL:[NSURL URLWithString:model.albumImg]]; [self.myImageView sd_setImageWithURL:[NSURL URLWithString:model.albumImg]]; self.songNameLabel.text = [NSString stringWithFormat:@"%@ - %@", model.singer, model.album]; self.authorSongLabel.text = model.title; }}else if (_type == PlayTypeNext) { if (self.index < self.myArr.count - 2) { CXSingListModel *model = self.myArr[self.index + 1]; NSString *str = model.url; NSString *str1 = [str stringByAppendingString:@"&ua=Iphone_Sst&version=4.2421&netType=1&toneFlag=1"]; [self.player playWithURL:str1]; [self.myImageView sd_setImageWithURL:[NSURL URLWithString:model.singerImg]]; self.authorSongLabel.text = model.title; self.songNameLabel.text = [NSString stringWithFormat:@"%@ - %@", model.singer, model.album]; }else { CXSingListModel *model = self.myArr[self.myArr.count - 1]; NSString *str = model.url; NSString *str1 = [str stringByAppendingString:@"&ua=Iphone_Sst&version=4.2421&netType=1&toneFlag=1"]; [self.player playWithURL:str1]; [self.myImageView sd_setImageWithURL:[NSURL URLWithString:model.singerImg]]; self.authorSongLabel.text = model.title; self.songNameLabel.text = [NSString stringWithFormat:@"%@ - %@", model.singer, model.album]; } }}#pragma mark - 监听播放 //监听实现的方法 - (void)playbackFinished:(NSNotification *)notificatio{ //然后播放下一曲 //判断是否是最后一曲,如果不是就重新赋值 //if (self.index != self.myArr.count - 1) { if (self.index != self.myArr.count - 1) {CXSingListModel *listMode = self.myArr[self.index + 1]; NSString *str = [listMode.url stringByAppendingString:@"&ua=Iphone_Sst&version=4.2421&netType=1&toneFlag=1"]; self.songId = str; //调用数据解析 [self createMusicData]; NSLog(@"下一首"); }else{ [self.player pause]; UIAlertController *mBoxView = [UIAlertController alertControllerWithTitle:@"嗨" message:@"已经最后一首了~" preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { [self dismissViewControllerAnimated:YES completion:^{}]; }]; UIAlertAction *otherAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { [self dismissViewControllerAnimated:YES completion:^{}]; }]; [mBoxView addAction:cancelAction]; [mBoxView addAction:otherAction]; [self presentViewController:mBoxView animated:YES completion:nil]; } }//播放按钮 - (void)clickPlay:(UIButton *)button{ self.isPlaying = !self.isPlaying; if (self.isPlaying) { [self.imgTimer setFireDate:[NSDate distantPast]]; [self resume]; //变成暂停按钮 [button setBackgroundImage:[UIImage imageNamed:@"stop"] forState:UIControlStateNormal]; }else{ //计时器暂停 [self.imgTimer setFireDate:[NSDate distantFuture]]; [self pause]; //暂停//变成播放按钮 [button setBackgroundImage:[UIImage imageNamed:@"songplay"] forState:UIControlStateNormal]; }}- (void)resume{ [self.player play]; }- (void)pause{ [self.player pause]; }//防止内存泄露 - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. }@end

完成后的效果图: 【iOS 模仿QQ音乐用Xcode写的一个播放器】iOS 模仿QQ音乐用Xcode写的一个播放器
文章图片

希望大家有什么好的想法,可以优化代码的地方私聊我,大家一起进步。加油

    推荐阅读