簡單的播放器實現(xiàn)

```

主要用到的控件有 AVPlayer?

該控件的初始化方法有許多種

- (instancetype)initWithURL:(NSURL *)URL?

+ (instancetype)playerWithURL:(NSURL *)URL

- (instancetype)initWithPlayerItem:(AVPlayerItem *)item

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

實現(xiàn)思路:

此處,我們將AVPlayer封裝在一個單例的工具類中,開放了這兩個接口.

+ (instancetype)sharePlayer;

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


1.隨意傳入一個播放的音頻網(wǎng)址,便可以對其進行播放,相關(guān)的布局,還可以通過屬性在外層VC內(nèi)進行賦值.

2.上下曲的邏輯部分通過通知中心傳到外層VC中,外層VC接受兩部分內(nèi)容,"點擊的音頻網(wǎng)址存入到一個數(shù)組當中"以及"點擊當前音頻的下標index",當前的下標是判斷上下曲的關(guān)鍵.



.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 {? ? ? ? // 在靜態(tài)區(qū),只初始化一次 創(chuàng)建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];? ? }// 返回按鈕方法實現(xiàn).

- (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 監(jiān)控// 給播放器添加進度更新

.- (void)addProgressObserver {? ? ??

? AVPlayerItem *playerItem = self.player.currentItem;??

? UIProgressView *progress = self.progress;? ? ?

?? // 設置每秒執(zhí)行一次.??

? [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(@"當前已經(jīng)播放了%.2fs",current);? ? ?

?? if (current) {? ? ? ?

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

? }? ? }];}

// 給AVPlayerItem添加監(jiān)控.

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

? ? // 監(jiān)控狀態(tài)屬性,注意AVPlayer也有一個status屬性,通過監(jiān)控它的status也可以獲得播放的狀態(tài).?

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

?? // 監(jiān)控網(wǎng)絡加載情況的屬性.?

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

// 移除AVPlayerItem上的監(jiān)控.

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

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

// 通過KVO監(jiān)控播放器的狀態(tài). keyPath:監(jiān)控屬性, object:監(jiān)視器, change:狀態(tài)改變, 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 {

// 在靜態(tài)區(qū),只初始化一次 創(chuàng)建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的內(nèi)容視圖更新.

[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的內(nèi)容視圖更新.

[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的內(nèi)容視圖更新.

[self reloadInputViews];

}

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

}

@end

```

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瘪吏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌戴质,老刑警劉巖芽狗,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隘膘,死亡現(xiàn)場離奇詭異旗芬,居然都是意外死亡纳击,警方通過查閱死者的電腦和手機朱灿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門昧识,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人盗扒,你說我怎么就攤上這事跪楞。” “怎么了侣灶?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵甸祭,是天一觀的道長。 經(jīng)常有香客問我褥影,道長池户,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任凡怎,我火速辦了婚禮校焦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘统倒。我一直安慰自己寨典,他們只是感情好,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布房匆。 她就那樣靜靜地躺著耸成,像睡著了一般。 火紅的嫁衣襯著肌膚如雪浴鸿。 梳的紋絲不亂的頭發(fā)上井氢,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機與錄音赚楚,去河邊找鬼毙沾。 笑死,一個胖子當著我的面吹牛宠页,可吹牛的內(nèi)容都是我干的左胞。 我是一名探鬼主播寇仓,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼烤宙!你這毒婦竟也來了遍烦?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤躺枕,失蹤者是張志新(化名)和其女友劉穎服猪,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拐云,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡罢猪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了叉瘩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膳帕。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖薇缅,靈堂內(nèi)的尸體忽然破棺而出危彩,到底是詐尸還是另有隱情,我是刑警寧澤泳桦,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布汤徽,位于F島的核電站,受9級特大地震影響灸撰,放射性物質(zhì)發(fā)生泄漏谒府。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一浮毯、第九天 我趴在偏房一處隱蔽的房頂上張望狱掂。 院中可真熱鬧,春花似錦亲轨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至讯嫂,卻和暖如春蹦锋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背欧芽。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工莉掂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人千扔。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓憎妙,卻偏偏與公主長得像库正,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子厘唾,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容