自定制视频播放器

由于项目需求很多时候我们需要自己设计一个视频播放器,其实说是自定制,主要是在UI上进行改变,以及一些功能细节上加以丰富,比如快进,快退,全屏等。

如果你只是简单实现视频播放,想要最懒的方式,可以不用往下看了,直接用MPMoviePlayerViewController就好

详细代码请参考https://github.com/gofey/LittleDemos里的视频播放器一项,已经封装成一个控件,下面只是介绍实现的过程和主要方法代码,


我是基于AVplayer进行的封装,首先需要三个元素(我也不知道该怎么称呼这几个,姑且这么叫吧)来获取和控制视频,如下:

self.playItem = [[AVPlayerItem alloc]initWithURL:self.video_url];

self.player = [AVPlayerplayerWithPlayerItem:self.playItem];

  self.playerLayer = [AVPlayerLayerplayerLayerWithPlayer:self.player];

初始化同时,注册通知

//播放完毕通知

        [[NSNotificationCenterdefaultCenter]addObserver:self

                                                selector:@selector(videoPlayDidEnd)

                                                    name:AVPlayerItemDidPlayToEndTimeNotification

                                                  object:nil];

        [[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(applicationWillResignActive:)

                                                    name:UIApplicationWillResignActiveNotificationobject:nil];//监听是否触发home键挂起程序.

        

        [[NSNotificationCenterdefaultCenter]addObserver:selfselector:@selector(applicationDidBecomeActive:)

                                                    name:UIApplicationDidBecomeActiveNotificationobject:nil];//监听是否重新进入程序程序.

       

初始化之后,就要添加观察者,监听事件

[playerItemaddObserver:selfforKeyPath:@"status"options:NSKeyValueObservingOptionNewcontext:nil];

   [playerItemaddObserver:selfforKeyPath:@"loadedTimeRanges"options:NSKeyValueObservingOptionNewcontext:nil];


然后是添加子控件

- (void)initSubViews:(CGRect)frame{

    CGFloat bottomViewW = frame.size.width;

    CGFloat bottomViewH =40;

    CGFloat bottomViewX =0;

    CGFloat bottomViewY = frame.size.height - bottomViewH;

    barHeight = bottomViewH;

    self.bottomView = [[BottomBaseViewalloc]initWithFrame:CGRectMake(bottomViewX, bottomViewY, bottomViewW, bottomViewH)];

    [selfaddSubview:self.bottomView];

    

    UIGestureRecognizer *gestureTap = [[UITapGestureRecognizeralloc]initWithTarget:selfaction:@selector(bottomGesture:)];

    

    [self.bottomViewaddGestureRecognizer:gestureTap];

    UIGestureRecognizer *gestureLongPress = [[UILongPressGestureRecognizeralloc]initWithTarget:selfaction:@selector(bottomGesture:)];

    [self.bottomViewaddGestureRecognizer:gestureLongPress];

    

    UIGestureRecognizer *gesturePan = [[UIPanGestureRecognizeralloc]initWithTarget:selfaction:@selector(bottomGesture:)];

    [self.bottomViewaddGestureRecognizer:gesturePan];

    

    

    

    self.bottomView.backgroundColor = [UIColorcolorWithRed:0green:0blue:0alpha:0.5];

    //    self.bottomView.timer = self.timer;

    

    self.playButton = [UIButtonbuttonWithType:UIButtonTypeCustom];

    [self.bottomViewaddSubview:self.playButton];

    self.playButton.frame =CGRectMake(0,0, bottomViewH, bottomViewH);

    [self.playButtonsetImage:[UIImageimageNamed:@"playBtnImg"]forState:UIControlStateNormal];

    [self.playButtonsetImage:[UIImageimageNamed:@"playBtnImgselected"]forState:UIControlStateSelected];

    [self.playButtonaddTarget:selfaction:@selector(playBtnTouchUpInside:)forControlEvents:UIControlEventTouchUpInside];

    CGFloat fillScreenButtonX = bottomViewW - bottomViewH;

    CGFloat fillScreenButtonY =0;

    CGFloat fillScreenButtonW = bottomViewH;

    CGFloat fillScreenButtonH = bottomViewH;

    self.fillScreenButton = [[UIButtonalloc]initWithFrame:CGRectMake(fillScreenButtonX, fillScreenButtonY, fillScreenButtonW, fillScreenButtonH)];

    [self.bottomViewaddSubview:self.fillScreenButton];

    [self.fillScreenButtonsetImage:[UIImageimageNamed:@"fillScreenBtnImg"]forState:UIControlStateNormal];

    [self.fillScreenButtonsetImage:[UIImageimageNamed:@"fillScreenBtnImgSelected"]forState:UIControlStateSelected];

    [self.fillScreenButtonaddTarget:selfaction:@selector(fillScreenButtonTouchUpInside:)forControlEvents:UIControlEventTouchUpInside];

    

    self.timeLabel = [[UILabelalloc]init];

    self.timeLabel.font = [UIFontsystemFontOfSize:17];

    

    self.timeLabel.text =@"00:00/00:00";

    [self.bottomViewaddSubview:self.timeLabel];

    

    self.timeLabel.textColor = [UIColorwhiteColor];

    self.timeLabel.textAlignment =NSTextAlignmentCenter;

    

    //计算实际frame大小,并将labelframe变成实际大小

    CGSize size =CGSizeMake(1000,10000);

    NSDictionary *attribute =@{NSFontAttributeName:self.timeLabel.font};

    CGSize labelsize = [self.timeLabel.textboundingRectWithSize:sizeoptions:NSStringDrawingTruncatesLastVisibleLine |NSStringDrawingUsesLineFragmentOrigin |NSStringDrawingUsesFontLeadingattributes:attributecontext:nil].size;

    

    CGFloat timeLabelY =0;

    CGFloat timeLabelW = labelsize.width +10;

    CGFloat timeLabelH = bottomViewH;

    CGFloat timeLabelX = bottomViewW - fillScreenButtonW - timeLabelW -10;

    self.timeLabel.frame =CGRectMake(timeLabelX, timeLabelY, timeLabelW, timeLabelH);

    

    

    CGFloat silderX =CGRectGetMaxX(self.playButton.frame) +15;

    CGFloat silderW = timeLabelX - silderX -15;

    CGFloat silderH =10;

    CGFloat silderY = (self.bottomView.bounds.size.height - silderH) / 2.0;

    self.playSlider = [[UISlideralloc]initWithFrame:CGRectMake(silderX, silderY, silderW, silderH)];

    [self.bottomViewaddSubview:self.playSlider];

    [self.playSlidersetThumbImage:[UIImageimageNamed:@"iconfont-yuan"]forState:UIControlStateNormal];

    [self.playSlidersetMinimumTrackTintColor:[UIColorblueColor] ];

    [self.playSlidersetMaximumTrackTintColor:[UIColorlightGrayColor]];

    [self.playSlideraddTarget:selfaction:@selector(progressValueChange:)forControlEvents:UIControlEventValueChanged];

    [self.playSlideraddTarget:selfaction:@selector(playSliderTouchUp:)forControlEvents:UIControlEventTouchUpInside];

    [self.playSlideraddTarget:selfaction:@selector(playSliderTouchUp:)forControlEvents:UIControlEventTouchUpOutside];

    

    

    [selfaddSubview:self.progressTipView];

    

}


还有隐藏和添加状态栏的方法

- (void)hideBottomBar{

    NSLog(@"hideBottomBar");

    self.hidenBar =YES;

    CGRect bottomRect =self.bottomView.frame;

    bottomRect.origin.y =self.bounds.size.height;

    [UIViewanimateWithDuration:0.4animations:^{

        self.bottomView.frame = bottomRect;

    }];

}

- (void)appearBottomBar{

    NSLog(@"appearBottomBar");

    self.hidenBar =NO;

    CGRect bottomRect =self.bottomView.frame;

    bottomRect.origin.y =self.bounds.size.height -self.bottomView.frame.size.height;

    [UIViewanimateWithDuration:0.4animations:^{

        self.bottomView.frame = bottomRect;

    }];

    self.timer = [NSTimerscheduledTimerWithTimeInterval:secondsTimertarget:selfselector:@selector(hideBottomBar)userInfo:nilrepeats:NO];


}

滑块控制进度的方法

- (void)progressValueChange:(UISlider *)sender{


    [self.timerinvalidate];

    if (self.player.rate == 0) {

        [self.playerseekToTime:CMTimeMake(sender.value*self.totalTime*10,10.0)];


    } elseif(self.player.rate ==1) {

        [selfpause];

        [self.playerseekToTime:CMTimeMake(sender.value*self.totalTime*10,10.0)];

    }else{

        NSLog(@"rate:%f",self.player.rate);

    }

    

}

监听事件

//添加avplayer block回调

- (void)addProgressObserver{

    __weak__typeof(self) weakSelf =self;

   //这里设置每秒执行一次

    [self.playeraddPeriodicTimeObserverForInterval:CMTimeMake(10.0,10.0)queue:dispatch_get_main_queue()usingBlock:^(CMTime time) {

        

        NSTimeInterval current =CMTimeGetSeconds(time);//获取当前的播放时间

   

        weakSelf.currentTime = current;

       //如果没有手动拖拽在进行自动更新

        

        [weakSelf.playSlidersetValue:(current /self.totalTime)animated:YES];

        //设置UILabel视图显示当前播放时长

        weakSelf.timeLabel.text = [weakSelfformatPlayTime:current];

    }];

}

//注册观察者监听状态和缓冲

- (void)addObserverWithPlayerItem:(AVPlayerItem *)playerItem

{

    [playerItem addObserver:selfforKeyPath:@"status"options:NSKeyValueObservingOptionNewcontext:nil];

    [playerItem addObserver:selfforKeyPath:@"loadedTimeRanges"options:NSKeyValueObservingOptionNewcontext:nil];

}

//移除观察者,移除监听

- (void)removeObserveWithPlayerItem:(AVPlayerItem *)playerItem

{

    [playerItem removeObserver:selfforKeyPath:@"loadedTimeRanges"];

    [playerItem removeObserver:selfforKeyPath:@"status"];

}

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

    AVPlayerItem *playItem = (AVPlayerItem *)object;

    if ([keyPathisEqualToString:@"status"]) {

        //当前播放器状态

        if ([playItemstatus] ==AVPlayerItemStatusReadyToPlay) {

            self.totalTime =CMTimeGetSeconds(playItem.duration);

            //[self playBtnTouchUpInside:self.playButton];

            self.timeLabel.text = [selfformatPlayTime:0.0f];

            self.progressTipLabel.text =self.timeLabel.text;

        }else{

            NSLog(@"这个视频有毒...");

        }

    }

    elseif([keyPathisEqualToString:@"loadedTimeRanges"]){

        //计算缓冲

    }

    else{

        NSLog(@"...");

    }

}

- (void)videoPlayDidEnd{

    NSLog(@"结束啦");

    [self.playItemsetReversePlaybackEndTime:kCMTimeZero];

    [self.playItemseekToTime:kCMTimeZero];

    [self.playSlidersetValue:0.0animated:YES];

    self.playButton.selected =NO;

}

- (void)applicationWillResignActive:(NSNotification *)notification


{

//    printf("按理说是触发home按下\n");

    if(self.player.rate == 1) {


        isPlay =YES;

        [selfpause];

    }else{

        isPlay =NO;

    }

}


- (void)applicationDidBecomeActive:(NSNotification *)notification

{

//    printf("按理说是重新进来后响应\n");

    if (isPlay) {

        [selfplay];

    }

}


全屏以及小屏方法

- (void)fillScreenButtonTouchUpInside:(UIButton *)sender

{

sender.selected = !sender.selected;

    if (sender.selected) {

        //进入全屏

        self.superView =self.superview;

        [self.windowaddSubview:self];

        [self.windowbringSubviewToFront:self];

        

        [UIViewanimateWithDuration:0.2fanimations:^{

            self.frame =CGRectMake(0,0, [UIScreenmainScreen].bounds.size.width, [UIScreenmainScreen].bounds.size.height);

            

            //            self.center = CGPointMake([UIScreen mainScreen].bounds.size.width/2.0, ([UIScreen mainScreen].bounds.size.height)/2.0);

            [selfupdateSubViewsFrame:self.frame];

        }];

        

    }

    else{

        //返回原状态

        [UIViewanimateWithDuration:0.2fanimations:^{

            //旋转360

            self.frame =self.originalFrame;

            

            [selfupdateSubViewsFrame:self.frame];

            [self.superViewaddSubview:self];

        }];

        

    }

    self.timer = [NSTimerscheduledTimerWithTimeInterval:secondsTimertarget:selfselector:@selector(hideBottomBar)userInfo:nilrepeats:NO];

}


- (void)updateSubViewsFrame:(CGRect )frame{

    

    [self.playerLayerremoveFromSuperlayer];

    self.playerLayer = [AVPlayerLayerplayerLayerWithPlayer:self.player];

    self.playerLayer.frame =self.bounds;

    [self.layeraddSublayer:self.playerLayer];

    

    [selfbringSubviewToFront:self.bottomView];

    CGFloat bottomViewW = frame.size.width;

    CGFloat bottomViewH =barHeight;

    CGFloat bottomViewX =0;

    CGFloat bottomViewY = frame.size.height - bottomViewH;

    self.bottomView.frame =CGRectMake(bottomViewX, bottomViewY, bottomViewW, bottomViewH);

    

    

    self.center =CGPointMake(self.frame.origin.x +self.frame.size.width/2.0,self.frame.origin.y +self.frame.size.height/2.0);

    

    self.playButton.frame =CGRectMake(0,0, bottomViewH, bottomViewH);

    CGFloat fillScreenButtonX = bottomViewW - bottomViewH;

    CGFloat fillScreenButtonY =0;

    CGFloat fillScreenButtonW = bottomViewH;

    CGFloat fillScreenButtonH = bottomViewH;

    

    self.fillScreenButton.frame =CGRectMake(fillScreenButtonX, fillScreenButtonY, fillScreenButtonW, fillScreenButtonH);

    

    CGSize size =CGSizeMake(1000,10000);

    NSDictionary *attribute =@{NSFontAttributeName:self.timeLabel.font};

    CGSize labelsize = [self.timeLabel.textboundingRectWithSize:sizeoptions:NSStringDrawingTruncatesLastVisibleLine |NSStringDrawingUsesLineFragmentOrigin |NSStringDrawingUsesFontLeadingattributes:attributecontext:nil].size;

    

    CGFloat timeLabelY =0;

    CGFloat timeLabelW = labelsize.width +10;

    CGFloat timeLabelH = bottomViewH;

    CGFloat timeLabelX = bottomViewW - fillScreenButtonW - timeLabelW -10;

    self.timeLabel.frame =CGRectMake(timeLabelX, timeLabelY, timeLabelW, timeLabelH);

    

    CGFloat silderX =CGRectGetMaxX(self.playButton.frame) +15;

    CGFloat silderW = timeLabelX - silderX -15;

    CGFloat silderH =10;

    CGFloat silderY = (self.bottomView.bounds.size.height - silderH) / 2.0;

    self.playSlider.frame =CGRectMake(silderX, silderY, silderW, silderH);

}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值