【iOS】ZFPlayer源码解读<上>

前言

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

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

635942-5662bfec6d457cba.png
说明

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

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


【iOS】ZFPlayer源码解读<上>_第1张图片
WX20181210-172911.png

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

Core文件夹中类与作用

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


【iOS】ZFPlayer源码解读<上>_第2张图片
Jietu20181210-105832.png

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

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

  • ZFPlayerController: 主类,所有的事件,回调视频,播放器,都由此获取。便于统一管理协作。
// 正常视频播放
+ (instancetype)playerWithPlayerManager:(id)playerManager containerView:(UIView *)containerView;

// 列表视频播放
+ (instancetype)playerWithScrollView:(UIScrollView *)scrollView playerManager:(id)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源码解读<上>)