iOS开发之常用技术点

【iOS】ZFPlayer源码解读<上>

2018-12-10  本文已影响88人  Colleny_Z
前言

最近看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都自定义了,那还要此库有何用?此库帮我们做了什么?我们为什么还要继续使用此库?

// 正常视频播放
+ (instancetype)playerWithPlayerManager:(id<ZFPlayerMediaPlayback>)playerManager containerView:(UIView *)containerView;

// 列表视频播放
+ (instancetype)playerWithScrollView:(UIScrollView *)scrollView playerManager:(id<ZFPlayerMediaPlayback>)playerManager containerViewTag:(NSInteger)containerViewTag;
@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;

// 将要失去焦点
@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);

注意:这几个方法只有当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];
}
- (void)zf_scrollViewDidEndDecelerating;
- (void)zf_scrollViewDidEndDraggingWillDecelerate:(BOOL)decelerate;
- (void)zf_scrollViewDidScrollToTop;
- (void)zf_scrollViewDidScroll;
- (void)zf_scrollViewWillBeginDragging;

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

最后

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


ZFPlayer源码解读<中>
上一篇下一篇

猜你喜欢

热点阅读