简单的播放器实现

```

主要用到的控件有 AVPlayer 

该控件的初始化方法有许多种

- (instancetype)initWithURL:(NSURL *)URL 

+ (instancetype)playerWithURL:(NSURL *)URL

- (instancetype)initWithPlayerItem:(AVPlayerItem *)item

+ (instancetype)playerWithPlayerItem:(AVPlayerItem *)item(最常用)

实现思路:

此处,我们将AVPlayer封装在一个单例的工具类中,开放了这两个接口.

+ (instancetype)sharePlayer;

- (void)playWithUrl:(NSURL *)url showView:(UIView *)showView;


1.随意传入一个播放的音频网址,便可以对其进行播放,相关的布局,还可以通过属性在外层VC内进行赋值.

2.上下曲的逻辑部分通过通知中心传到外层VC中,外层VC接受两部分内容,"点击的音频网址存入到一个数组当中"以及"点击当前音频的下标index",当前的下标是判断上下曲的关键.



.h

////  PlayerSingle.h//  喜马拉雅FM////  Created by dllo on 16/3/7.//  Copyright © 2016年 lanou.com. All rights reserved.//#import#import#import@interface PlayerSingle : NSObject

// 视图层面.

@property (nonatomic, retain) UIImageView *imageBackGroundView;

@property (nonatomic, retain) UILabel *labelForTitle;

@property (nonatomic, retain) UIImageView *imageCoverLarge;

// 功能层面.

@property (nonatomic, retain) UIView *visualView;

@property (nonatomic, retain) AVPlayer *player;

@property (nonatomic, retain) AVPlayerItem *playerItem;

@property (nonatomic, retain) UIButton *buttonPlayOrPause;

@property (nonatomic, retain) UIButton *buttonRight;

@property (nonatomic, retain) UIButton *buttonLeft;

@property (nonatomic, retain) UIProgressView *progress;

+ (instancetype)sharePlayer;

- (void)playWithUrl:(NSURL *)url showView:(UIView *)showView;

@end



.m

////  PlayerSingle.m//  喜马拉雅FM////  Created by dllo on 16/3/7.//  Copyright © 2016年 lanou.com. All rights reserved.//#define WIDTH [UIScreen mainScreen].bounds.size.width#define HEIGHT [UIScreen mainScreen].bounds.size.height#import "PlayerSingle.h"#import#import@implementation PlayerSingle

- (void)dealloc {  [_imageBackGroundView release];  [_labelForTitle release];  [_imageCoverLarge release];              [_visualView release];    [_player release];    [_playerItem release];    [_buttonPlayOrPause release];    [_buttonRight release];    [_buttonLeft release];    [_progress release];    [super dealloc];}

+ (instancetype)sharePlayer {        // 在静态区,只初始化一次 创建ItemVC3对象.    static PlayerSingle *player = nil;   

 static dispatch_once_t predicate;      

  dispatch_once(&predicate, ^{    

    player = [[PlayerSingle alloc]init];    });     

   return player;}

- (instancetype)init {  

  self = [super init]; 

   if (self) {            }    

return self;}

- (void)playWithUrl:(NSURL *)url showView:(UIView *)showView {        self.imageBackGroundView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"2.jpg"]];    

self.imageBackGroundView.frame = showView.bounds;    [showView addSubview:self.imageBackGroundView];    self.imageBackGroundView.userInteractionEnabled = YES;    [self.imageBackGroundView release];      

  UIBlurEffect *blur = [UIBlurEffect effectWithStyle:2];  

  self.visualView = [[UIVisualEffectView alloc]initWithEffect:blur];    self.visualView.frame = showView.bounds;   

 [self.imageBackGroundView addSubview:self.visualView];  

  [self.visualView release];       

 UIButton *backButton = [UIButton buttonWithType:UIButtonTypeCustom];    backButton.frame = CGRectMake(10, 24, 32, 32);  

  [backButton setBackgroundImage:[UIImage imageNamed:@"fanhui"] forState:UIControlStateNormal];   

 [showView addSubview:backButton];   

 [backButton addTarget:self action:@selector(backButton:) forControlEvents:UIControlEventTouchUpInside];      

  UIButton *naozhongButton = [UIButton buttonWithType:UIButtonTypeCustom];    naozhongButton.frame = CGRectMake(WIDTH - 40, 24, 32, 32);    [naozhongButton setBackgroundImage:[UIImage imageNamed:@"naozhong"] forState:UIControlStateNormal];   

 [showView addSubview:naozhongButton];      

  self.labelForTitle = [[UILabel alloc]initWithFrame:CGRectMake(50, 20, WIDTH - 100, 60)];  

  [showView addSubview:self.labelForTitle];  

  self.labelForTitle.text = @"主题";   

 self.labelForTitle.font = [UIFont systemFontOfSize:20];    self.labelForTitle.textColor = [UIColor whiteColor];    self.labelForTitle.numberOfLines = 0;   

 self.labelForTitle.textAlignment = NSTextAlignmentCenter;   

 [self.labelForTitle release];      

  self.imageCoverLarge = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"2.jpg"]];  

  self.imageCoverLarge.frame = CGRectMake((WIDTH - (HEIGHT - 60 - 300)) / 2, 110, HEIGHT - 60 - 300, HEIGHT - 60 - 300);  

  [showView addSubview:self.imageCoverLarge];   

 [self.imageCoverLarge release];    

        self.progress = [[UIProgressView alloc]initWithProgressViewStyle:UIProgressViewStyleDefault];    self.progress.frame = CGRectMake(50, HEIGHT - 200, [UIScreen mainScreen].bounds.size.width - 100, 30);  

  self.progress.backgroundColor = [UIColor greenColor];  

  [showView addSubview:self.progress];  

  [self.progress release];               

 self.buttonPlayOrPause = [UIButton buttonWithType:UIButtonTypeCustom];        self.buttonPlayOrPause.frame = CGRectMake((WIDTH - 50) / 2, HEIGHT - 150, 50, 50);       

 [showView addSubview:self.buttonPlayOrPause];    

    [self.buttonPlayOrPause setBackgroundImage:[UIImage imageNamed:@"zanting2"] forState:UIControlStateNormal];        [self.buttonPlayOrPause addTarget:self action:@selector(handleAction:) forControlEvents:UIControlEventTouchUpInside];       

         self.buttonRight = [UIButton buttonWithType:UIButtonTypeCustom];        self.buttonRight.frame = CGRectMake((WIDTH - 50) / 2 + 70, HEIGHT - 150, 50, 50);    

    [showView addSubview:self.buttonRight];    

    [self.buttonRight setBackgroundImage:[UIImage imageNamed:@"xiayiqu"] forState:UIControlStateNormal];    

    [self.buttonRight addTarget:self action:@selector(handleButtonRight:) forControlEvents:UIControlEventTouchUpInside];       

     self.buttonLeft = [UIButton buttonWithType:UIButtonTypeCustom];        self.buttonLeft.frame = CGRectMake((WIDTH - 50) / 2 - 70, HEIGHT - 150, 50, 50);       

 [showView addSubview:self.buttonLeft];    

    [self.buttonLeft setBackgroundImage:[UIImage imageNamed:@"shangyiqu"] forState:UIControlStateNormal];     

   [self.buttonLeft addTarget:self action:@selector(handleButtonLeft:) forControlEvents:UIControlEventTouchUpInside];     

       self.playerItem = [AVPlayerItem playerItemWithURL:url];     

   self.player = [AVPlayer playerWithPlayerItem:self.playerItem];     

   [self.player play];        

    [self addProgressObserver];//     

   [self addObserverToPlayerItem:self.playerItem];    }// 返回按钮方法实现.

- (void)backButton:(UIButton *)button {     

   NSNotification *notice = [NSNotification notificationWithName:@"返回" object:nil];  

  [[NSNotificationCenter defaultCenter]postNotification:notice];}

#pragma mark UIButton的点击方法.// 播放按钮的点击事件

- (void)handleAction:(UIButton *)button {     

   if (button.selected) {      

  [self.buttonPlayOrPause setBackgroundImage:[UIImage imageNamed:@"zanting2"] forState:UIControlStateNormal];     

   [self.player play];  

  }else {    

    [self.buttonPlayOrPause setBackgroundImage:[UIImage imageNamed:@"bofang2"] forState:UIControlStateNormal];  

      [self.player pause];    }  

  button.selected = !button.selected;

}

- (void)handleButtonRight:(UIButton *)button {   

     NSNotification *notice = [NSNotification notificationWithName:@"下一曲" object:nil];  

  [[NSNotificationCenter defaultCenter]postNotification:notice];  

  }

- (void)handleButtonLeft:(UIButton *)button {     

   NSNotification *notice = [NSNotification notificationWithName:@"上一曲" object:nil];   

 [[NSNotificationCenter defaultCenter]postNotification:notice];}

#pragma mark 监控// 给播放器添加进度更新

.- (void)addProgressObserver {      

  AVPlayerItem *playerItem = self.player.currentItem;  

  UIProgressView *progress = self.progress;     

   // 设置每秒执行一次.  

  [self.player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {   

     float current = CMTimeGetSeconds(time);    

    float total = CMTimeGetSeconds([playerItem duration]);     

   //        NSLog(@"当前已经播放了%.2fs",current);     

   if (current) {       

     [progress setProgress:(current/total) animated:YES];      

  }    }];}

// 给AVPlayerItem添加监控.

- (void)addObserverToPlayerItem:(AVPlayerItem *)playerItem {    

    // 监控状态属性,注意AVPlayer也有一个status属性,通过监控它的status也可以获得播放的状态. 

   [playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];     

   // 监控网络加载情况的属性. 

   [playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];}

// 移除AVPlayerItem上的监控.

- (void)removeObserverFromPlayerItem:(AVPlayerItem *)playerItem {      [playerItem removeObserver:self forKeyPath:@"status"];  

  [playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];}

// 通过KVO监控播放器的状态. keyPath:监控属性, object:监视器, change:状态改变, context:上下文.

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void *)context {

AVPlayerItem *playerItem = object;

if ([keyPath isEqualToString:@"status"]) {

AVPlayerStatus status = [[change objectForKey:@"new"] intValue];

if (status == AVPlayerStatusReadyToPlay) {

NSLog(@"正在播放.....,视频总长度为:%.2f",CMTimeGetSeconds(playerItem.duration));

}

}else if([keyPath isEqualToString:@"loadedTimeRanges"]) {

NSArray *array = playerItem.loadedTimeRanges;

// 本次缓冲范围.

CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];

float startSecends = CMTimeGetSeconds(timeRange.start);

float durationSecends = CMTimeGetSeconds(timeRange.duration);

// 缓冲总长度.

NSTimeInterval totalBuffer = startSecends + durationSecends;

NSLog(@"共缓冲:%.2f",totalBuffer);

}

}

@end


VC部分的代码:

.h

////  ItemVC3.h//  喜马拉雅FM////  Created by dllo on 16/1/22.//  Copyright © 2016年 lanou.com. All rights reserved.//#import@class ModelForSecendVC;

@interface ItemVC3 : UIViewController

@property (nonatomic, retain) NSString *musicUrlString;

@property (nonatomic, retain) ModelForSecendVC *model;

@property (nonatomic, retain) NSMutableArray *arrForModel;

@property (nonatomic, assign) NSInteger index;

+ (instancetype)shareItemVC3;

@end


.m

////  ItemVC3.m//  喜马拉雅FM////  Created by dllo on 16/1/22.//  Copyright © 2016年 lanou.com. All rights reserved.//#define WIDTH [UIScreen mainScreen].bounds.size.width#define HEIGHT [UIScreen mainScreen].bounds.size.height#import "ItemVC3.h"#import "ModelForSecendVC.h"#import "UIImageView+WebCache.h"#import#import#import "Player.h"

#import "PlayerSingle.h"

@interface ItemVC3 ()

@property (nonatomic, retain) NSMutableArray *arrForUrl;

@end

@implementation ItemVC3

+ (instancetype)shareItemVC3 {

// 在静态区,只初始化一次 创建ItemVC3对象.

static ItemVC3 *itemThree = nil;

static dispatch_once_t predicate;

dispatch_once(&predicate, ^{

itemThree = [[ItemVC3 alloc]init];

});

return itemThree;

}

#pragma mark ViewController的生命周期.

- (void)viewWillAppear:(BOOL)animated {

}

- (void)viewDidLoad {

[super viewDidLoad];

[self.navigationController setNavigationBarHidden:YES animated:YES];

NSString *urlStr = self.musicUrlString;

urlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

NSURL *url = [NSURL URLWithString:urlStr];

self.arrForUrl = [NSMutableArray array];

for (ModelForSecendVC *model in self.arrForModel) {

[self.arrForUrl addObject:model.playUrl64];

}

[[PlayerSingle sharePlayer]playWithUrl:url showView:self.view];

[self getValue];

// 通知中心记得移除,代理方法记得置空.dealloc.

NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

[center addObserver:self selector:@selector(handleBack:) name:@"返回" object:nil];

[center addObserver:self selector:@selector(handleXiaYiQu:) name:@"下一曲" object:nil];

[center addObserver:self selector:@selector(handleShangYiQu:) name:@"上一曲" object:nil];

}

// 给播放界面的赋值.

- (void)getValue {

[[PlayerSingle sharePlayer].imageBackGroundView sd_setImageWithURL:[NSURL URLWithString:self.model.coverLarge]];

[[PlayerSingle sharePlayer].imageCoverLarge sd_setImageWithURL:[NSURL URLWithString:self.model.coverLarge]];

[PlayerSingle sharePlayer].labelForTitle.text = self.model.title;

}

- (void)handleBack:(NSNotificationCenter *)center {

[self dismissViewControllerAnimated:YES completion:nil];

}

- (void)handleXiaYiQu:(NSNotificationCenter *)center {

NSLog(@"下一曲");

if (self.index < self.arrForModel.count - 1) {

[[PlayerSingle sharePlayer].player replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithURL:[NSURL URLWithString:self.arrForUrl[self.index + 1]]]];

ModelForSecendVC *model = self.arrForModel[self.index + 1];

[[PlayerSingle sharePlayer].imageBackGroundView sd_setImageWithURL:[NSURL URLWithString:model.coverLarge]];

[[PlayerSingle sharePlayer].imageCoverLarge sd_setImageWithURL:[NSURL URLWithString:model.coverLarge]];

[PlayerSingle sharePlayer].labelForTitle.text = model.title;

// VC的内容视图更新.

[self reloadInputViews];

self.index++;

}else {

self.index = 0;

[[PlayerSingle sharePlayer].player replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithURL:[NSURL URLWithString:self.arrForUrl[0]]]];

ModelForSecendVC *model = self.arrForModel[0];

[[PlayerSingle sharePlayer].imageBackGroundView sd_setImageWithURL:[NSURL URLWithString:model.coverLarge]];

[[PlayerSingle sharePlayer].imageCoverLarge sd_setImageWithURL:[NSURL URLWithString:model.coverLarge]];

[PlayerSingle sharePlayer].labelForTitle.text = model.title;

}

}

- (void)handleShangYiQu:(NSNotificationCenter *)center {

NSLog(@"上一曲");

if (self.index > 0) {

[[PlayerSingle sharePlayer].player replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithURL:[NSURL URLWithString:self.arrForUrl[self.index - 1]]]];

ModelForSecendVC *model = self.arrForModel[self.index - 1];

[[PlayerSingle sharePlayer].imageBackGroundView sd_setImageWithURL:[NSURL URLWithString:model.coverLarge]];

[[PlayerSingle sharePlayer].imageCoverLarge sd_setImageWithURL:[NSURL URLWithString:model.coverLarge]];

[PlayerSingle sharePlayer].labelForTitle.text = model.title;

// VC的内容视图更新.

[self reloadInputViews];

self.index--;

}else {

self.index = self.arrForModel.count - 1;

[[PlayerSingle sharePlayer].player replaceCurrentItemWithPlayerItem:[AVPlayerItem playerItemWithURL:[NSURL URLWithString:self.arrForUrl[self.arrForModel.count - 1]]]];

ModelForSecendVC *model = self.arrForModel[self.arrForModel.count - 1];

[[PlayerSingle sharePlayer].imageBackGroundView sd_setImageWithURL:[NSURL URLWithString:model.coverLarge]];

[[PlayerSingle sharePlayer].imageCoverLarge sd_setImageWithURL:[NSURL URLWithString:model.coverLarge]];

[PlayerSingle sharePlayer].labelForTitle.text = model.title;

// VC的内容视图更新.

[self reloadInputViews];

}

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

}

@end

```

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,233评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,013评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,030评论 0 241
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,827评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,221评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,542评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,814评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,513评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,225评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,497评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,998评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,342评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,986评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,812评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,560评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,461评论 2 266

推荐阅读更多精彩内容