```
主要用到的控件有 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
```