//
//??MZPlayView.m
//??視頻播放器常規(guī)功能
//
//??Created?by?yubo?on?16/7/27.
//
#import?"MZPlayView.h"
#import?
#import?
#import?
/**
*??Description
關(guān)于視頻這一塊的業(yè)務(wù)操作全部封裝在這個(gè)里面。?對(duì)外就提供一個(gè)NSUrl屬性。
*/
typedefNS_ENUM(NSInteger,PanDirection){
PanDirectionHorizontalMoved,//橫向移動(dòng)
PanDirectionVerticalMoved//縱向移動(dòng)
};
@interfaceMZPlayView()
@property(nonatomic,strong)AVPlayer*player;
@property(nonatomic,strong)AVPlayerItem*playerItem;
@property(nonatomic,strong)AVPlayerLayer*playerLayer;
@property(weak,nonatomic)?IBOutletUIButton*backBtn;
@property(weak,nonatomic)?IBOutletUILabel*forwardLabel;
@property(weak,nonatomic)?IBOutletUILabel*currentTimeLabel;
@property(weak,nonatomic)?IBOutletUIProgressView*progressView;
@property(weak,nonatomic)?IBOutletUILabel*totalTimeLabel;
@property(weak,nonatomic)?IBOutletUIButton*fullScreanBtn;
@property(weak,nonatomic)?IBOutletUISlider*sliderView;
@property(weak,nonatomic)?IBOutletUIButton*startBtn;
@property(weak,nonatomic)?IBOutletUIButton*lockBtn;
@property(nonatomic,assign)boolplayViewFlag;//?隱藏和顯示標(biāo)識(shí)
@property(nonatomic,strong)NSTimer*timer;
@property(nonatomic,assign)boollockFlag;//?鎖標(biāo)識(shí)
@property(nonatomic,assign)?PanDirection?panDirection;
@property(nonatomic,?assign)BOOLisVolume;//?是否調(diào)節(jié)音量
@property(nonatomic,strong)UISlider*volumeViewSlider;
@property(nonatomic,?assign)?CGFloat?sumTime;//?用來保存的總時(shí)長(zhǎng)
@end
@implementationMZPlayView
-?(void)awakeFromNib{
[superawakeFromNib];
[_sliderViewsetThumbImage:[UIImageimageNamed:@"slider"]forState:UIControlStateNormal];
[selfinsertSubview:_progressViewbelowSubview:_sliderView];
//?滑塊左邊的顏色
_sliderView.minimumTrackTintColor=?[UIColororangeColor];
//?滑塊右邊的顏色
_sliderView.maximumTrackTintColor=?[UIColorclearColor];
}
-?(void)setUrl:(NSURL*)url{
_playerItem?=?[AVPlayerItemplayerItemWithURL:url];
_player?=?[AVPlayerplayerWithPlayerItem:_playerItem];
_playerLayer?=?[AVPlayerLayerplayerLayerWithPlayer:_player];
[self.layerinsertSublayer:_playerLayeratIndex:0];
[_playerplay];
_forwardLabel.hidden=YES;
//?添加播完通知
[[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(moviePlayDidEnd:)name:AVPlayerItemDidPlayToEndTimeNotificationobject:_player.currentItem];
//?添加手勢(shì)
[selfcreateGesture];
//獲取系統(tǒng)音量
[selfconfigureVolume];
//?添加事件
[selfsliderAddEvent];
//?通過定時(shí)器獲取?時(shí)間,
_timer?=?[NSTimerscheduledTimerWithTimeInterval:1.0ftarget:selfselector:@selector(playerTimerAction)userInfo:nilrepeats:YES];
//?計(jì)算緩沖
[_playerItemaddObserver:selfforKeyPath:@"loadedTimeRanges"options:NSKeyValueObservingOptionNewcontext:nil];
[_playerItemaddObserver:selfforKeyPath:@"status"options:NSKeyValueObservingOptionNewcontext:nil];
}
#pragma?mark??滑動(dòng)事件添加
-?(void)sliderAddEvent{
//?slider開始滑動(dòng)事件
[_sliderViewaddTarget:selfaction:@selector(progressSliderTouchBegan:)forControlEvents:UIControlEventTouchDown];
//?slider滑動(dòng)中事件
[_sliderViewaddTarget:selfaction:@selector(progressSliderValueChanged:)forControlEvents:UIControlEventValueChanged];
//?slider結(jié)束滑動(dòng)事件
[_sliderViewaddTarget:selfaction:@selector(progressSliderTouchEnded:)forControlEvents:UIControlEventTouchUpInside];
}
//?開始滑動(dòng)
-?(void)progressSliderTouchBegan:(UISlider*)slider{
//?取消延遲
//????[NSObject?cancelPreviousPerformRequestsWithTarget:self];
}
//?開始變化
-?(void)progressSliderValueChanged:(UISlider*)slider{
//?拖動(dòng)改變視頻播放進(jìn)度
if(_player.status==?AVPlayerItemStatusReadyToPlay)?{
//?總秒數(shù)
CGFloat?total?=?(CGFloat)_playerItem.duration.value/?_playerItem.duration.timescale;
//?已經(jīng)拖動(dòng)到了現(xiàn)在的秒數(shù)了。
NSInteger?dragedSeconds?=?floorf(total*?slider.value);
//轉(zhuǎn)換成CMTime才能給player來控制播放進(jìn)度---這個(gè)類用來控制時(shí)間的。
CMTime?dragedCMTime?=?CMTimeMake(dragedSeconds,1);
[_playerpause];
[_playerseekToTime:dragedCMTimecompletionHandler:^(BOOLfinished)?{
[_playerplay];
}];
}
}
#pragma?mark?slider事件結(jié)束
-?(void)progressSliderTouchEnded:(UISlider*)slider{
}
#pragma?mark?重新布局?frame
-?(void)layoutSubviews{
_playerLayer.frame=self.bounds;
};
#pragma?mark?添加手勢(shì),?點(diǎn)擊隱藏視頻所有按鈕
-?(void)createGesture{
UITapGestureRecognizer*tap?=?[[UITapGestureRecognizeralloc]initWithTarget:selfaction:@selector(playViewHanlder:)];
tap.numberOfTapsRequired=1;
[selfaddGestureRecognizer:tap];
}
#pragma?mark?手勢(shì)回調(diào)處理
-?(void)playViewHanlder:(UITapGestureRecognizer*)recognizer{
if(!_lockFlag)?{
if(recognizer.state==?UIGestureRecognizerStateRecognized)?{
if(!_playViewFlag)?{
[selfhiddlePlayView];
}else{
[selfshowPlayView];
}
}
}
}
#pragma?mark?隱藏組件
-?(void)hiddlePlayView{
[UIViewanimateWithDuration:0.5animations:^{
_backBtn.alpha=0;
_currentTimeLabel.alpha=0;
_progressView.alpha=0;
_totalTimeLabel.alpha=0;
_fullScreanBtn.alpha=0;
_sliderView.alpha=0;
_startBtn.alpha=0;
}completion:^(BOOLfinished)?{
_playViewFlag?=?!_playViewFlag;
}];
}
#pragma?mark?顯示組件
-?(void)showPlayView{
[UIViewanimateWithDuration:0.5animations:^{
_backBtn.alpha=1;
_currentTimeLabel.alpha=1;
_progressView.alpha=1;
_totalTimeLabel.alpha=1;
_fullScreanBtn.alpha=1;
_sliderView.alpha=1;
_startBtn.alpha=1;
}completion:^(BOOLfinished)?{
_playViewFlag?=?!_playViewFlag;
}];
}
#pragma?mark??播放完后---通知處理
-?(void)moviePlayDidEnd:(NSNotification*)notification{
}
#pragma?mark?播放或者暫停
-?(IBAction)startAction:(id)sender?{
UIButton*btn?=?(UIButton*)sender;
if(btn.selected)?{
[_playerplay];
}else{
[_playerpause];
}
btn.selected=?!btn.selected;
}
#pragma?mark?全屏按鈕事件
-?(IBAction)fullScreanAction:(id)sender?{
UIDeviceOrientation?orientation?=?[UIDevicecurrentDevice].orientation;
UIInterfaceOrientation?interfaceOrientation?=?(UIInterfaceOrientation)orientation;
switch(interfaceOrientation)?{
caseUIInterfaceOrientationPortraitUpsideDown://?電池欄在下
[selfinterfaceOrientation:UIInterfaceOrientationLandscapeRight];
break;
caseUIInterfaceOrientationPortrait://?電池欄在上
[selfinterfaceOrientation:UIInterfaceOrientationLandscapeRight];
break;
caseUIInterfaceOrientationLandscapeLeft://?電池欄在右邊
[selfinterfaceOrientation:UIInterfaceOrientationPortrait];
break;
caseUIInterfaceOrientationLandscapeRight://?電池欄左邊
[selfinterfaceOrientation:UIInterfaceOrientationPortrait];
break;
default:
break;
}
}
#pragma?mark??強(qiáng)制轉(zhuǎn)屏相關(guān)
-?(void)interfaceOrientation:(UIInterfaceOrientation)orientation{
//?arc下
if([[UIDevicecurrentDevice]respondsToSelector:@selector(setOrientation:)])?{
SELselector?=?NSSelectorFromString(@"setOrientation:");
NSInvocation*invocation?=?[NSInvocationinvocationWithMethodSignature:[UIDeviceinstanceMethodSignatureForSelector:selector]];
[invocationsetSelector:selector];
[invocationsetTarget:[UIDevicecurrentDevice]];
intval?=?orientation;
[invocationsetArgument:&valatIndex:2];
[invocationinvoke];
}
}
#pragma?mark?通過定時(shí)器獲取視頻的時(shí)間問題
-?(void)playerTimerAction{
if(_playerItem.duration.timescale!=0)?{
_sliderView.maximumValue=1;//音樂總共時(shí)長(zhǎng)
_sliderView.value=?CMTimeGetSeconds([_playerItemcurrentTime])?/?(_playerItem.duration.value/?_playerItem.duration.timescale);//當(dāng)前進(jìn)度
//duration?總時(shí)長(zhǎng)
NSInteger?durMin?=?(NSInteger)_playerItem.duration.value/?_playerItem.duration.timescale;//總秒
NSInteger?durSec?=?(NSInteger)_playerItem.duration.value/?_playerItem.duration.timescale/60;//總分鐘
_totalTimeLabel.text=?[NSStringstringWithFormat:@"%02ld:%02ld",durSec,durMin];
//當(dāng)前時(shí)長(zhǎng)進(jìn)度progress
NSInteger?proMin?=?(NSInteger)CMTimeGetSeconds([_playerItemcurrentTime]);//當(dāng)前秒
NSInteger?proSec?=?(NSInteger)CMTimeGetSeconds([_playerItemcurrentTime])?/60;//當(dāng)前分
_currentTimeLabel.text=?[NSStringstringWithFormat:@"%02ld:%02ld",?proSec,proMin];
}
}
#pragma?mark?計(jì)算出總時(shí)間
-?(void)observeValueForKeyPath:(NSString*)keyPathofObject:(id)objectchange:(NSDictionary?*)changecontext:(voidvoid*)context{
if(object?==?_playerItem)?{
if([keyPathisEqualToString:@"status"])?{//?這里代表添加完成
if(_playerItem.status==?AVPlayerItemStatusReadyToPlay)?{
//?添加滑動(dòng)手勢(shì)
UIPanGestureRecognizer*pan?=?[[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(panDirection:)];
[selfaddGestureRecognizer:pan];
}
}elseif([keyPathisEqualToString:@"loadedTimeRanges"]){
NSTimeInterval?timeInterval?=?[selfavailableDuration];//?計(jì)算緩沖進(jìn)度
CMTime??duration?=?_playerItem.duration;
CGFloat?totalDuration?=?CMTimeGetSeconds(duration);
[_progressViewsetProgress:timeInterval?/?totalDurationanimated:NO];
}
}
}
#pragma?mark??計(jì)算緩存
-?(NSTimeInterval)availableDuration?{
NSArray*loadedTimeRanges?=?[[_playercurrentItem]loadedTimeRanges];
CMTimeRange?timeRange?=?[loadedTimeRanges.firstObjectCMTimeRangeValue];//?獲取緩沖區(qū)域
floatstartSeconds?=?CMTimeGetSeconds(timeRange.start);
floatdurationSeconds?=?CMTimeGetSeconds(timeRange.duration);
NSTimeInterval?result?=?startSeconds?+?durationSeconds;//?計(jì)算緩沖總進(jìn)度
returnresult;
}
#pragma?mark?鎖屏
-?(IBAction)lockAction:(id)sender?{
UIButton*btn?=?(UIButton*)sender;
btn.selected=?!btn.selected;
_lockFlag?=?btn.selected;
if(btn.selected)?{
[btnsetImage:[UIImageimageNamed:@"lock-nor"]forState:UIControlStateNormal];
}else{
[btnsetImage:[UIImageimageNamed:@"unlock-nor"]forState:UIControlStateNormal];
}
}
#pragma?mark???平移手勢(shì)
-?(void)panDirection:(UIPanGestureRecognizer*)pan{
//?根據(jù)在Uiview的位置,調(diào)節(jié)音量或者亮度
CGPoint?locationPoint?=?[panlocationInView:self];
NSLog(@"當(dāng)前點(diǎn)的位置--->%@",NSStringFromCGPoint(locationPoint));
//?拖動(dòng)的速度---->返回值就是你拖動(dòng)時(shí)X和Y軸上的速度,速度是矢量,有方向
CGPoint?veloctyPoint?=?[panvelocityInView:self];
NSLog(@"拖動(dòng)的速度--->%@",NSStringFromCGPoint(veloctyPoint));
//?判斷是垂直移動(dòng)還是水平移動(dòng)
switch(pan.state)?{
caseUIGestureRecognizerStateBegan:{//?開始移動(dòng)
CGFloat?x?=?fabs(veloctyPoint.x);
CGFloat?y?=?fabs(veloctyPoint.y);
if(x?>?y)?{//?水平移動(dòng)
_panDirection?=?PanDirectionHorizontalMoved;
CMTime?time?=?_player.currentTime;
_sumTime?=?time.value/time.timescale;
NSLog(@"===%f",_sumTime);
}elseif(x?<?y){//?垂直移動(dòng)
_panDirection?=?PanDirectionVerticalMoved;
if(locationPoint.x>self.bounds.size.width/2)?{//?右邊是控制音量
_isVolume?=true;
}else{//?左邊是控制亮度
_isVolume?=false;
}
}
}
break;
caseUIGestureRecognizerStateChanged:{//?正在移動(dòng)
if(self.panDirection==?PanDirectionHorizontalMoved)?{//?水平
[selfhorizontalMoved:veloctyPoint.x];//?水平移動(dòng)的方法只要x方向的值
}else{//?垂直
[selfverticalMoved:veloctyPoint.y];//?垂直移動(dòng)方法只要y方向的值
}
}
break;
caseUIGestureRecognizerStateEnded:{
NSLog(@"移動(dòng)停止l......");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,?(int64_t)(11*?NSEC_PER_SEC)),?dispatch_get_main_queue(),?^{
//?隱藏視圖
_forwardLabel.hidden=YES;
});
if(self.panDirection==?PanDirectionHorizontalMoved)?{
//轉(zhuǎn)換成CMTime才能給player來控制播放進(jìn)度
CMTime?dragedCMTime?=?CMTimeMake(self.sumTime,1);
[_playerpause];
[_playerseekToTime:dragedCMTimecompletionHandler:^(BOOLfinish){
[_playerplay];
}];
//?把sumTime滯空,不然會(huì)越加越多
self.sumTime=0;
}else{
}
}
break;
default:
break;
}
}
#pragma?mark???垂直移動(dòng)處理。
-?(void)verticalMoved:(CGFloat)value{
if(_isVolume)?{//?控制音量
//?更改系統(tǒng)的音量
self.volumeViewSlider.value-=?value?/10000;//?越小幅度越小
//?這個(gè)就對(duì)手機(jī)有效果,?最大的值為?1??。
NSLog(@"聲音----->%lf",self.volumeViewSlider.value);
}else{//?調(diào)節(jié)亮度
[UIScreenmainScreen].brightness-=?value?/10000;
NSString*brightness?=?[NSStringstringWithFormat:@"亮度%.0f%%",[UIScreenmainScreen].brightness/1.0*100];
_forwardLabel.hidden=NO;
_forwardLabel.text=?brightness;
}
}
//獲取系統(tǒng)音量
-?(void)configureVolume
{
//?系統(tǒng)聲音控制
MPVolumeView*volumeView?=?[[MPVolumeViewalloc]init];
_volumeViewSlider?=nil;
for(UIView*view?in?[volumeViewsubviews]){
if([view.class.descriptionisEqualToString:@"MPVolumeSlider"]){
_volumeViewSlider?=?(UISlider*)view;
break;
}
}
//?使用這個(gè)category的應(yīng)用不會(huì)隨著手機(jī)靜音鍵打開而靜音,可在手機(jī)靜音下播放聲音
NSError*setCategoryError?=nil;
BOOLsuccess?=?[[AVAudioSessionsharedInstance]
setCategory:?AVAudioSessionCategoryPlayback
error:?&setCategoryError];
if(!success)?{/*?handle?the?error?in?setCategoryError?*/}
}
#pragma?mark?-?pan水平移動(dòng)的方法
-?(void)horizontalMoved:(CGFloat)value{
//?快進(jìn)快退的方法
NSString*style?=@"";
if(value?<0)?{
style?=@"<<";
}
elseif(value?>0){
style?=@">>";
}
//?每次滑動(dòng)需要疊加時(shí)間
self.sumTime+=?value?/200;
//?需要限定sumTime的范圍
CMTime?totalTime?=self.playerItem.duration;
CGFloat?totalMovieDuration?=?(CGFloat)totalTime.value/totalTime.timescale;
if(self.sumTime>?totalMovieDuration)?{
self.sumTime=?totalMovieDuration;
}elseif(self.sumTime<0){
self.sumTime=0;
}
//?當(dāng)前快進(jìn)的時(shí)間
NSString*nowTime?=?[selfdurationStringWithTime:(int)self.sumTime];
//?總時(shí)間
NSString*durationTime?=?[selfdurationStringWithTime:(int)totalMovieDuration];
//?給label賦值
_forwardLabel.text=?[NSStringstringWithFormat:@"%@?%@?/?%@",style,?nowTime,durationTime];
_forwardLabel.hidden=NO;
}
#pragma?mark?-?根據(jù)時(shí)長(zhǎng)求出字符串
-?(NSString*)durationStringWithTime:(int)time
{
//?獲取分鐘
NSString*min?=?[NSStringstringWithFormat:@"%02d",time?/60];
//?獲取秒數(shù)
NSString*sec?=?[NSStringstringWithFormat:@"%02d",time?%60];
return[NSStringstringWithFormat:@"%@:%@",?min,sec];
}
@end
視圖只設(shè)置了 ? 6+ 的適配, 其他的沒做處理。
調(diào)用
self.view.backgroundColor = [UIColor blackColor];
[objc]view plaincopy
NSURL*url?=?[NSURLURLWithString:@"http://baobab.wdjcdn.com/14562919706254.mp4"];
NSURL*url?=?[[NSBundlemainBundle]URLForResource:@"minion_01"withExtension:@"mp4"];
[_playViewsetUrl:url];
效果:
實(shí)現(xiàn)了, ?暫停, 拖放,聲音,亮度, 鎖屏。 這一些基本簡(jiǎn)單操作。