美文网首页iOS开发之常用技术点
【iOS】ZFPlayer源码解读<上>

【iOS】ZFPlayer源码解读<上>

作者: Colleny_Z | 来源:发表于2018-12-10 19:58 被阅读88次
    前言

    最近看AVFoundation音视频类的东西,有了解到开源视频播放器ZFPlayer,在这里解读顺便了解学习一下作者的设计思路,如有不足或者错误,希望读者能够批评并指正。

    这是作者对此框架的设计脑图。根据类名可以看出作者是按功能模块将之拆成了不同的类,这样结构比较清晰便于重用与组件化。

    635942-5662bfec6d457cba.png
    说明

    用法作者在原文章有介绍用法原著,在这里只是解读研究源码与实现思路。

    ZFPlayer 3.2.2 目前包含以下五个文件夹:


    WX20181210-172911.png

    在这里我也根据使用方法与功能模块,分为上中下3篇介绍,本篇为上篇,主要介绍 Core文件夹下相关类。使用pod 'ZFPlayer', '~> 3.0'安装即可。

    Core文件夹中类与作用

    安装成功后,所pod下来的文件是core文件夹,如下图:


    Jietu20181210-105832.png

    就像作者所说,这只是一个播放器的壳子,如果你想完全自定义 播放器AVPlayer控制视图AVPlayerControlView,这些文件就够了。但是,自定义的player需要严格遵循协议实现 ZFPlayerMediaPlayback协议并实现,自定义的controlView需要遵循ZFPlayerMediaControl协议,根据回调更新自定义的controlView。

    既然player与controlView都自定义了,那还要此库有何用?此库帮我们做了什么?我们为什么还要继续使用此库?

    • ZFPlayerController: 主类,所有的事件,回调视频,播放器,都由此获取。便于统一管理协作。
    // 正常视频播放
    + (instancetype)playerWithPlayerManager:(id<ZFPlayerMediaPlayback>)playerManager containerView:(UIView *)containerView;
    
    // 列表视频播放
    + (instancetype)playerWithScrollView:(UIScrollView *)scrollView playerManager:(id<ZFPlayerMediaPlayback>)playerManager containerViewTag:(NSInteger)containerViewTag;
    
    • ZFOrientationObserver:封装了有关屏幕旋转,监听,布局更新。
      视频播放时,我们可根据协议使用来自定义自己的业务与相关布局。

    • ZFKVOController: 更加安全的使用KVO ( 与播放器直接业务逻辑无关 ),避免在直接使用时带来的一些因多次过度释放导致程序crash的副作用。建议参考一下facebook早期的的开源库FBKVOController

    • ZFPlayerGestureControl:多种手势管理的一个类,主要用于播放器的controlView,里面包含点击,双击,捏合,拖动等等,并优化了用户在使用播放器间这些手势间的之间的一些冲突。这些作者都已经帮我们完成并把手势识别的结果回调给我们,我们以此来操作控制层ControlView(UI)与播放器本身(逻辑)的业务如播放进度,播放器的暂停,播放,快进快退等等。

    @property (nonatomic, copy, nullable) void(^singleTapped)(ZFPlayerGestureControl *control);
    @property (nonatomic, copy, nullable) void(^doubleTapped)(ZFPlayerGestureControl *control);
    @property (nonatomic, copy, nullable) void(^beganPan)(ZFPlayerGestureControl *control, ZFPanDirection direction, ZFPanLocation location);
    @property (nonatomic, copy, nullable) void(^changedPan)(ZFPlayerGestureControl *control, ZFPanDirection direction, ZFPanLocation location, CGPoint velocity);
    @property (nonatomic, copy, nullable) void(^endedPan)(ZFPlayerGestureControl *control, ZFPanDirection direction, ZFPanLocation location);
    
    // 捏合
    @property (nonatomic, copy, nullable) void(^pinched)(ZFPlayerGestureControl *control, float scale);
    
    // 拖动方向,一开始是左右拖动的方向,或者是上下拖动的方向
    @property (nonatomic, readonly) ZFPanDirection panDirection;
    
    // 所处屏幕位置,如左边调节音量,右侧调整亮度
    @property (nonatomic, readonly) ZFPanLocation panLocation;
    @property (nonatomic, readonly) ZFPanMovingDirection panMovingDirection;
    
    
    • ZFPlayerLogManager:日志类,根据配置环境可实时查看控制台的一些相关的播放信息便于调试,这里不多说。

    • ZFPlayerNotification: 播放器系统的相关通知监听:包括前后,耳机插拔,音量等,如果自定义,根据此回调处理自身业务,当然如果这些不满足,可自行再添加回调,只是不方便使用pod了。

    // 将要失去焦点
    @property (nonatomic, copy, nullable) void(^willResignActive)(ZFPlayerNotification *registrar);
    
    // 已经变更为活跃
    @property (nonatomic, copy, nullable) void(^didBecomeActive)(ZFPlayerNotification *registrar);
    
    // 插入耳机
    @property (nonatomic, copy, nullable) void(^newDeviceAvailable)(ZFPlayerNotification *registrar);
    
    // 拔出耳机
    @property (nonatomic, copy, nullable) void(^oldDeviceUnavailable)(ZFPlayerNotification *registrar);
    
    // AVAudioSession对象的category发生改变时
    @property (nonatomic, copy, nullable) void(^categoryChange)(ZFPlayerNotification *registrar);
    
    // 音量改变
    @property (nonatomic, copy, nullable) void(^volumeChanged)(float volume);
    
    • ZFPlayerView : 基类,自己实现继承于此类,作者原码也是这样也实现的,后面会再写。

    • ZFReachabilityManager : 网络状态监听,同Reachability,AFNetworking...,因为库本身功能确实依赖网络状态,又避免使用者项目中可能会存在冲突,就为自己加了一个便一统一,也避免使用者麻烦。

    • ZFFloatView : 全局的小浮窗视图,可跟随手指的拖动而移动(UIPanGestureRecognizer),此类并无播放器相关业务。

    • UIViewController+ZFPlayerRotation: 方便控制当前的ViewController支持旋转及旋转的方向,里面重写的系统方法,有关屏幕旋转网上的解释也非常多,更多详情这里可以参考iOS 屏幕旋转。代码很固定,重写方法的字面意思也很好理解,用的时候根据自身业务与框架提供的布尔值即可,只是一个方向问题,难度不大,只是需要适配各种旋转情况。

    注意:这几个方法只有当viewController是window的rootViewController或者viewController是present出来时,才会起作用!,所以如果想让各个viewController来控制自己的方向,重写UINavigationController,UITabbarController,UIViewController中固定的相关旋转的方法即可

    1. UITabbarController中重写以下方法
    // 子控制器是否支持旋转
    - (BOOL)shouldAutorotate {
        UIViewController *vc = self.viewControllers[self.selectedIndex];
        if ([vc isKindOfClass:[UINavigationController class]]) {
            UINavigationController *nav = (UINavigationController *)vc;
            return [nav.topViewController shouldAutorotate];
        } else {
            return [vc shouldAutorotate];
        }
    }
    
    // 子控制器支持旋转的所有方向,多选
    - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
        UIViewController *vc = self.viewControllers[self.selectedIndex];
        if ([vc isKindOfClass:[UINavigationController class]]) {
            UINavigationController *nav = (UINavigationController *)vc;
            return [nav.topViewController supportedInterfaceOrientations];
        } else {
            return [vc supportedInterfaceOrientations];
        }
    }
    
    // 子控制器优先支持的方向
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
        UIViewController *vc = self.viewControllers[self.selectedIndex];
        if ([vc isKindOfClass:[UINavigationController class]]) {
            UINavigationController *nav = (UINavigationController *)vc;
            return [nav.topViewController preferredInterfaceOrientationForPresentation];
        } else {
            return [vc preferredInterfaceOrientationForPresentation];
        }
    }
    
    1. UINavigationController重写以下方法
    // 同上
    - (BOOL)shouldAutorotate {
        return [self.topViewController shouldAutorotate];
    }
    
    // 同上
    - (UIInterfaceOrientationMask)supportedInterfaceOrientations {
        return [self.topViewController supportedInterfaceOrientations];
    }
    
    // 同上
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
        return [self.topViewController preferredInterfaceOrientationForPresentation];
    }
    
    • UIScrollView+ZFPlayer : 滚动中在可视范围内播放,类似微博首页中的视频。这个类传入列表视图,里面会自动根据偏移计算位置并在设定的位置播放,此类里面大多是关于坐标的计算与列表的偏移更新,但是需要使用者自己主动调用以下以下代理。
    - (void)zf_scrollViewDidEndDecelerating;
    - (void)zf_scrollViewDidEndDraggingWillDecelerate:(BOOL)decelerate;
    - (void)zf_scrollViewDidScrollToTop;
    - (void)zf_scrollViewDidScroll;
    - (void)zf_scrollViewWillBeginDragging;
    

    以上这些类是被定义在Core文件夹下,然而并没有丝毫有关播放器与控制视图的任务业务逻辑。

    最后

    ZFPlayer最初版本并不是以协议为基准分散到各个类去实现,后来更新了整个功能结构采用协议进行自由定制与复用,每个类的所实现的功能点比较明确单一,这样也便于维护拓展,背后可以看出作者很用心并且此库更新的版本也比较快。
    使用途中,最好组件复用,比如使用了ZFReachabilityManager,若项目中之前存在ReachabilityManager网络监听类可以保留其一,避免重复。


    ZFPlayer源码解读<中>

    相关文章

      网友评论

        本文标题:【iOS】ZFPlayer源码解读<上>

        本文链接:https://www.haomeiwen.com/subject/bjxrhqtx.html