博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用AVPlayer自定义支持全屏的播放器(四)
阅读量:5882 次
发布时间:2019-06-19

本文共 8215 字,大约阅读时间需要 27 分钟。

前言

前段时间封装了一个视频播放器,经过一段时间的测试,发现了许多bug,针对以前遗留的问题进行了修复和更新。

修复bug

主要修复了播放器页面不支持旋转引起全屏音量图标未旋转,进度条拖拽不灵敏,Masonry引起约束警告,网络不好销毁播放器引起卡顿,工具条自动消失后需要点击两次等bug。

1.旋转后音量图标不旋转bug

开始使用的是旋转播放器来实现全屏,实际页面未旋转,所以系统音量图标方向不对,修改后利用页面旋转来实现全屏,这样就不会引起系统音量图标方向不对,具体如何使页面支持旋转,并且不影响其他页面请看这里。

2.进度条拖拽不灵敏

由于自定义了进度条的图标,引起进度条拖拽不灵敏,这里在自定义进度条内部重写- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event这两个方法,增大响应的范围。

代码
//检查点击事件点击范围是否能够交给self处理- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {    //调用父类方法,找到能够处理event的view    UIView* result = [super hitTest:point withEvent:event];    if (result != self) {        /*如果这个view不是self,我们给slider扩充一下响应范围,         这里的扩充范围数据就可以自己设置了         */        if ((point.y >= -15) &&            (point.y < (_lastBounds.size.height + SLIDER_Y_BOUND)) &&            (point.x >= 0 && point.x < CGRectGetWidth(self.bounds))) {            //如果在扩充的范围类,就将event的处理权交给self            result = self;        }    }    //否则,返回能够处理的view    return result;}//检查是点击事件的点是否在slider范围内- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {    //调用父类判断    BOOL result = [super pointInside:point withEvent:event];    if (!result) {        //同理,如果不在slider范围类,扩充响应范围        if ((point.x >= (_lastBounds.origin.x - SLIDER_X_BOUND)) && (point.x <= (_lastBounds.origin.x + _lastBounds.size.width + SLIDER_X_BOUND))            && (point.y >= -SLIDER_Y_BOUND) && (point.y < (_lastBounds.size.height + SLIDER_Y_BOUND))) {            //在扩充范围内,返回yes            result = YES;        }    }    //否则返回父类的结果    return result;}复制代码

新增功能

新增加了转子动画,增加拖拽后转子衔接动画,增加各类接口。

转子动画

利用CAShapeLayerUIBezierPath做了一个简单的加载动画。

代码
@interface AILoadingView ()
@property(nonatomic,strong)CAShapeLayer *loadingLayer;/** 当前的index*/@property(nonatomic,assign)NSInteger index;/** 是否能用*/@property(nonatomic,assign,getter=isEnable)BOOL enable;@end@implementation AILoadingView- (instancetype)initWithFrame:(CGRect)frame{ self = [super initWithFrame:frame]; if (self) { _index = 0; _enable = YES; _duration = 2.; [self createUI]; } return self;}-(void)layoutSubviews { [super layoutSubviews]; UIBezierPath *path = [self cycleBezierPathIndex:_index]; self.loadingLayer.path = path.CGPath;}- (UIBezierPath*)cycleBezierPathIndex:(NSInteger)index { UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height *0.5) radius:self.bounds.size.width * 0.5 startAngle:index * (M_PI* 2)/3 endAngle:index * (M_PI* 2)/3 + 2*M_PI * 4/3 clockwise:YES]; return path;}- (void)createUI { self.loadingLayer = [CAShapeLayer layer]; self.loadingLayer.lineWidth = 2.; self.loadingLayer.fillColor = [UIColor clearColor].CGColor; self.loadingLayer.strokeColor = [UIColor blackColor].CGColor; [self.layer addSublayer:self.loadingLayer]; self.loadingLayer.lineCap = kCALineCapRound;}- (void)loadingAnimation { CABasicAnimation *strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; strokeStartAnimation.fromValue = @0; strokeStartAnimation.toValue = @1.; strokeStartAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; CABasicAnimation *strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; strokeEndAnimation.fromValue = @.0; strokeEndAnimation.toValue = @1.; strokeEndAnimation.duration = self.duration * 0.5; CAAnimationGroup *strokeAniamtionGroup = [CAAnimationGroup animation]; strokeAniamtionGroup.duration = self.duration; strokeAniamtionGroup.delegate = self; strokeAniamtionGroup.animations = @[strokeEndAnimation,strokeStartAnimation]; [self.loadingLayer addAnimation:strokeAniamtionGroup forKey:@"strokeAniamtionGroup"];}#pragma mark -CAAnimationDelegate-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { if (!self.isEnable) { return; } _index++; self.loadingLayer.path = [self cycleBezierPathIndex:_index %3].CGPath; [self loadingAnimation];}#pragma mark -public- (void)starAnimation { if (self.loadingLayer.animationKeys.count > 0) { return; } self.hidden = NO; self.enable = YES; [self loadingAnimation];}- (void)stopAnimation { self.hidden = YES; self.enable = NO; [self.loadingLayer removeAllAnimations];}- (void)setStrokeColor:(UIColor *)strokeColor { _strokeColor = strokeColor; self.loadingLayer.strokeColor = strokeColor.CGColor;}复制代码

使用方法

使用cocoapods导入,pod 'CLPlayer'

1.普通页面

支持通过Push和模态创建的页面,无论页面是否支持旋转都兼容。播放器默认全部页面都只支持竖屏,如果使用后需要某个页面支持其他方向,需要重写下面几个方法。

页面支持其他方向代码
#pragma mark -- 需要页面支持其他方向,需要重写这三个方法,默认所有页面只支持竖屏// 是否支持自动转屏- (BOOL)shouldAutorotate {    return YES;}// 支持哪些屏幕方向- (UIInterfaceOrientationMask)supportedInterfaceOrientations {    return UIInterfaceOrientationMaskAll;}// 默认的屏幕方向(当前ViewController必须是通过模态出来的UIViewController(模态带导航的无效)方式展现出来的,才会调用这个方法)- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {    return UIInterfaceOrientationPortrait;}复制代码
使用代码
CLPlayerView *playerView = [[CLPlayerView alloc] initWithFrame:CGRectMake(0, 90, self.view.CLwidth, 300)];        [self.view addSubview:playerView];    //    //重复播放,默认不播放//    playerView.repeatPlay = YES;//    //当前控制器是否支持旋转,当前页面支持旋转的时候需要设置,告知播放器//    playerView.isLandscape = YES;//    //设置等比例全屏拉伸,多余部分会被剪切//    playerView.fillMode = ResizeAspectFill;//    //设置进度条背景颜色//    playerView.progressBackgroundColor = [UIColor purpleColor];//    //设置进度条缓冲颜色//    playerView.progressBufferColor = [UIColor redColor];//    //设置进度条播放完成颜色//    playerView.progressPlayFinishColor = [UIColor greenColor];//    //全屏是否隐藏状态栏//    playerView.fullStatusBarHidden = NO;//    //是否静音,默认NO//    playerView.mute = YES;//    //转子颜色//    playerView.strokeColor = [UIColor redColor];    //视频地址    playerView.url = [NSURL URLWithString:@"http://baobab.wdjcdn.com/14587093851044544c.mp4"];    //播放    [playerView playVideo];    //返回按钮点击事件回调    [playerView backButton:^(UIButton *button) {        NSLog(@"返回按钮被点击");        //查询是否是全屏状态        NSLog(@"%d",playerView.isFullScreen);    }];    //播放完成回调    [playerView endPlay:^{        //销毁播放器//        [playerView destroyPlayer];//        playerView = nil;        NSLog(@"播放完成");    }];复制代码

2.TableVIew使用代码

创建方式和普通页面一样,在创建的时候记录播放器所在cell,在cell滑出当前TableView的时候对播放器进行销毁。

播放器创建代码
#pragma mark - 点击播放代理- (void)cl_tableViewCellPlayVideoWithCell:(CLTableViewCell *)cell{    //记录被点击的Cell    _cell = cell;    //销毁播放器    [_playerView destroyPlayer];    CLPlayerView *playerView = [[CLPlayerView alloc] initWithFrame:CGRectMake(0, 0, cell.CLwidth, cell.CLheight)];    _playerView = playerView;    [cell.contentView addSubview:_playerView];//    //重复播放,默认不播放//    _playerView.repeatPlay = YES;//    //当前控制器是否支持旋转,当前页面支持旋转的时候需要设置,告知播放器//    _playerView.isLandscape = YES;//    //设置等比例全屏拉伸,多余部分会被剪切//    _playerView.fillMode = ResizeAspectFill;//    //设置进度条背景颜色//    _playerView.progressBackgroundColor = [UIColor purpleColor];//    //设置进度条缓冲颜色//    _playerView.progressBufferColor = [UIColor redColor];//    //设置进度条播放完成颜色//    _playerView.progressPlayFinishColor = [UIColor greenColor];//    //全屏是否隐藏状态栏//    _playerView.fullStatusBarHidden = NO;//    //转子颜色//    _playerView.strokeColor = [UIColor redColor];    //视频地址    _playerView.url = [NSURL URLWithString:cell.model.videoUrl];    //播放    [_playerView playVideo];    //返回按钮点击事件回调    [_playerView backButton:^(UIButton *button) {        NSLog(@"返回按钮被点击");    }];    //播放完成回调    [_playerView endPlay:^{        //销毁播放器        [_playerView destroyPlayer];        _playerView = nil;        _cell = nil;        NSLog(@"播放完成");    }];}复制代码
判断cell是否滑出TableView代码
//cell离开tableView时调用- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{    //因为复用,同一个cell可能会走多次    if ([_cell isEqual:cell]) {        //区分是否是播放器所在cell,销毁时将指针置空        [_playerView destroyPlayer];        _cell = nil;    }}复制代码

播放器效果图

总结

本次主要是修复以前遗留的bug,完善了各种情况的Demo,优化了体验,Demo中有详细的注释,具体请在github下载 , 如果喜欢,欢迎star。

转载地址:http://ygpix.baihongyu.com/

你可能感兴趣的文章
renhook的使用
查看>>
DOCKER windows 7 详细安装教程
查看>>
养眼美女绿色壁纸
查看>>
U盘启动盘制作工具箱 v1.0
查看>>
增强myEclipse的提示功能
查看>>
Zabbix汉化方法
查看>>
Java I/O系统基础知识
查看>>
Java多线程设计模式(2)生产者与消费者模式
查看>>
对象并不一定都是在堆上分配内存的
查看>>
刘宇凡:罗永浩的锤子情怀只能拿去喂狗
查看>>
php晚了8小时 PHP5中的时间相差8小时的解决办法
查看>>
JS(JavaScript)的初了解7(更新中···)
查看>>
svn文件管理器的使用
查看>>
Ansible playbook 使用
查看>>
for/foreach/linq执行效率测试
查看>>
js /jquery停止事件冒泡和阻止浏览器默认事件
查看>>
长春理工大学第十四届程序设计竞赛(重现赛)I.Fate Grand Order
查看>>
好作品地址
查看>>
[翻译]Protocol Buffer 基础: C++
查看>>
runloop与线程的关系
查看>>