# SJVideoPlayer **Repository Path**: lijunchengit/SJVideoPlayer ## Basic Information - **Project Name**: SJVideoPlayer - **Description**: 功能齐全的视频播放器 - **Primary Language**: Objective-C - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 13 - **Created**: 2019-08-28 - **Last Updated**: 2025-02-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README  [](https://travis-ci.org/changsanjiang/SJVideoPlayer) [](https://cocoapods.org/pods/SJVideoPlayer) [](https://github.com/changsanjiang) [](https://github.com/changsanjiang/SJVideoPlayer/blob/master/LICENSE.md) ### Installation ```ruby # Player with default control layer. pod 'SJVideoPlayer' # The base player, without the control layer, can be used if you need a custom control layer. pod 'SJBaseVideoPlayer' # 天朝 # 如果网络不行安装不了, 可改成以下方式进行安装 pod 'SJBaseVideoPlayer', :git => 'https://gitee.com/changsanjiang/SJBaseVideoPlayer.git' pod 'SJVideoPlayer', :git => 'https://gitee.com/changsanjiang/SJVideoPlayer.git' pod 'SJUIKit/AttributesFactory', :git => 'https://gitee.com/changsanjiang/SJUIKit.git' pod 'SJUIKit/ObserverHelper', :git => 'https://gitee.com/changsanjiang/SJUIKit.git' pod 'SJUIKit/Queues', :git => 'https://gitee.com/changsanjiang/SJUIKit.git' $ pod update --no-repo-update (不要用 pod install 了, 用这个命令安装) ``` - [Base Video Player](https://github.com/changsanjiang/SJBaseVideoPlayer) ___ ## Contact * Email: changsanjiang@gmail.com ___ ## License SJVideoPlayer is available under the MIT license. See the LICENSE file for more info. ___ ## 最近更新 * 适配 iOS 13.0. * v2.6.0 开始 旋转的配置已从播放器内部移出, 现在需开发者自己添加配置, 代码如下: ```Objective-C static BOOL _iPhone_shouldAutorotate(UIViewController *vc) { NSString *class = NSStringFromClass(vc.class); // 禁止哪些控制器旋转. // - 如果返回 NO, 则只旋转`播放器`. // - 如果返回 YES, 则`所有控制器`同`播放器`一起旋转. // // return NO; // - 为了避免控制器同播放器一起旋转, 此处禁止Demo中SJ前缀的控制器旋转. if ( [class hasPrefix:@"SJ"] ) { return NO; } // 其余情况 return YES. 此时系统的播放器(如在网页播放全屏后)可以触发旋转. return YES; } @implementation UIViewController (RotationControl) /// 该控制器是否可以旋转 - (BOOL)shouldAutorotate { // 此处为设置 iPhone 哪些控制器可以旋转 if ( UIUserInterfaceIdiomPhone == UI_USER_INTERFACE_IDIOM() ) return _iPhone_shouldAutorotate(self); return NO; } /// 旋转支持的方向 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { // 此处为设置 iPhone 某个控制器旋转支持的方向 // - 请根据实际情况进行修改. if ( UIUserInterfaceIdiomPhone == UI_USER_INTERFACE_IDIOM() ) { // 如果self不支持旋转, 返回仅支持竖屏 if ( _iPhone_shouldAutorotate(self) == NO ) return UIInterfaceOrientationMaskPortrait; } return UIInterfaceOrientationMaskAllButUpsideDown; } @end @implementation UITabBarController (RotationControl) - (UIViewController *)sj_topViewController { if ( self.selectedIndex == NSNotFound ) return self.viewControllers.firstObject; return self.selectedViewController; } - (BOOL)shouldAutorotate { return [[self sj_topViewController] shouldAutorotate]; } - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return [[self sj_topViewController] supportedInterfaceOrientations]; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return [[self sj_topViewController] preferredInterfaceOrientationForPresentation]; } @end @implementation UINavigationController (RotationControl) - (BOOL)shouldAutorotate { return self.topViewController.shouldAutorotate; } - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return self.topViewController.supportedInterfaceOrientations; } - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return self.topViewController.preferredInterfaceOrientationForPresentation; } - (nullable UIViewController *)childViewControllerForStatusBarStyle { return self.topViewController; } - (nullable UIViewController *)childViewControllerForStatusBarHidden { return self.topViewController; } @end ``` * 新增 切换清晰度的控制层. 开启如下: ```Objective-C SJVideoPlayerURLAsset *asset1 = [[SJVideoPlayerURLAsset alloc] initWithURL:VideoURL_Level4]; asset1.definition_fullName = @"超清 1080P"; asset1.definition_lastName = @"超清"; SJVideoPlayerURLAsset *asset2 = [[SJVideoPlayerURLAsset alloc] initWithURL:VideoURL_Level3]; asset2.definition_fullName = @"高清 720P"; asset2.definition_lastName = @"AAAAAAA"; SJVideoPlayerURLAsset *asset3 = [[SJVideoPlayerURLAsset alloc] initWithURL:VideoURL_Level2]; asset3.definition_fullName = @"清晰 480P"; asset3.definition_lastName = @"480P"; _player.definitionURLAssets = @[asset1, asset2, asset3]; // 先播放asset1. (asset2 和 asset3 将会在用户选择后进行切换) _player.URLAsset = asset1; ``` * 新增 左右边缘快进快退. 开启如下: ```Objective-C // 开启左右边缘快进快退. 如需进行更多配置, 请查看`fastForwardViewController` _player.fastForwardViewController.enabled = YES; ``` * 新增 小浮窗播放. 开启如下: ```Objective-C // 开启小浮窗. 如需进行更多配置, 请查看`floatSmallViewController` _player.floatSmallViewController.enabled = YES; ``` ___ ## Documents #### [1 视图层次](#1) * [1.1 在普通 View 上播放](#1.1) * [1.2 在 TableViewCell 上播放](#1.2) * [1.3 在 TableHeaderView 或者 TableFooterView 上播放](#1.3) * [1.4 在 CollectionViewCell 上播放](#1.4) * [1.5 CollectionView 嵌套在 TableViewHeaderView 中, 在 CollectionViewCell 上播放](#1.5) * [1.6 CollectionView 嵌套在 TableViewCell 中, 在 CollectionViewCell 上播放](#1.6) * [1.7 CollectionView 嵌套在 CollectionViewCell 中, 在 CollectionViewCell 上播放](#1.7) * [1.8 在 UITableViewHeaderFooterView 上播放](#1.8) #### [2. 创建资源进行播放](#2) * [2.1 通过 URL 创建资源进行播放](#2.1) * [2.2 通过 AVAsset 或其子类进行播放](#2.2) * [2.3 指定开始播放的时间](#2.3) * [2.4 续播. 进入下个页面时, 继续播放](#2.4) * [2.5 销毁时的回调. 可在此时做一些记录工作, 如播放位置](#2.5) #### [3. 播放控制](#3) * [3.1 当前时间和时长](#3.1) * [3.2 时间改变时的回调](#3.2) * [3.3 播放结束后的回调](#3.3) * [3.4 播放状态 - 未知/准备/准备就绪/播放中/暂停的/不活跃的](#3.4) * [3.5 暂停的原因 - 缓冲/跳转/暂停](#3.5) * [3.6 不活跃的原因 - 加载失败/播放完毕](#3.6) * [3.7 播放状态改变的回调](#3.7) * [3.8 是否自动播放 - 当资源初始化完成后](#3.8) * [3.9 刷新 ](#3.9) * [3.10 播放器的声音设置 & 静音](#3.10) * [3.11 播放](#3.11) * [3.12 暂停](#3.12) * [3.13 是否暂停 - 当App进入后台后](#3.13) * [3.14 停止](#3.14) * [3.15 重播](#3.15) * [3.16 跳转到指定的时间播放](#3.16) * [3.17 调速 & 速率改变时的回调](#3.17) * [3.18 接入别的视频 SDK, 自己动手撸一个 SJMediaPlaybackController, 替换作者原始实现](#3.18) #### [4. 控制层的显示和隐藏](#4) * [4.1 让控制层显示](#4.1) * [4.2 让控制层隐藏](#4.2) * [4.3 控制层是否显示中](#4.3) * [4.4 是否在暂停时保持控制层显示](#4.4) * [4.5 是否自动显示控制层 - 资源初始化完成后](#4.5) * [4.6 控制层显示状态改变的回调](#4.6) * [4.7 禁止管理控制层的显示和隐藏](#4.7) * [4.8 自己动手撸一个 SJControlLayerAppearManager, 替换作者原始实现](#4.8) #### [5. 设备亮度和音量](#5) * [5.1 调整设备亮度](#5.1) * [5.2 调整设备声音](#5.2) * [5.3 亮度 & 声音改变后的回调](#5.3) * [5.4 禁止播放器设置](#5.4) * [5.5 自己动手撸一个 SJDeviceVolumeAndBrightnessManager, 替换作者原始实现](#5.5) #### [6. 旋转](#6) * [6.1 自动旋转](#6.1) * [6.2 设置自动旋转支持的方向](#6.2) * [6.3 禁止自动旋转](#6.3) * [6.4 主动调用旋转](#6.4) * [6.5 是否全屏](#6.5) * [6.6 是否正在旋转](#6.6) * [6.7 当前旋转的方向 ](#6.7) * [6.8 旋转开始和结束的回调](#6.8) * [6.9 自己动手撸一个 SJRotationManager, 替换作者原始实现](#6.9) #### [7. 直接全屏而不旋转](#7) * [7.1 全屏和恢复](#7.1) * [7.2 开始和结束的回调](#7.2) * [7.3 是否是全屏](#7.3) * [7.4 自己动手撸一个 SJFitOnScreenManager, 替换作者原始实现](#7.4) #### [8. 镜像翻转](#8) * [8.1 翻转和恢复](#8.1) * [8.2 开始和结束的回调](#8.2) * [8.3 自己动手撸一个 SJFlipTransitionManager, 替换作者原始实现](#8.3) #### [9. 网络状态](#9) * [9.1 当前的网络状态](#9.1) * [9.2 网络状态改变的回调](#9.2) * [9.3 自己动手撸一个 SJReachability, 替换作者原始实现](#9.3) #### [10. 手势](#10) * [10.1 单击手势](#10.1) * [10.2 双击手势](#10.2) * [10.3 移动手势](#10.3) * [10.4 捏合手势](#10.4) * [10.5 禁止某些手势](#10.5) * [10.6 自定义某个手势的处理](#10.6) * [10.7 自己动手撸一个 SJPlayerGestureControl, 替换作者原始实现](#10.7) #### [11. 占位图](#11) * [11.1 设置本地占位图](#11.1) * [11.2 设置网络占位图](#11.2) * [11.3 是否隐藏占位图 - 播放器准备好显示时](#11.3) #### [12. 显示提示文本](#12) * [12.1 显示文本及持续时间 - (NSString or NSAttributedString)](#12.1) * [12.2 配置提示文本](#12.2) #### [13. 一些固定代码](#13) * [13.1 - (void)vc_viewDidAppear; ](#13.1) * [13.2 - (void)vc_viewWillDisappear;](#13.2) * [13.3 - (void)vc_viewDidDisappear;](#13.3) * [13.4 - (BOOL)vc_prefersStatusBarHidden;](#13.4) * [13.5 - (UIStatusBarStyle)vc_preferredStatusBarStyle;](#13.5) * [13.6 - 临时显示状态栏](#13.6) * [13.7 - 临时隐藏状态栏](#13.7) #### [14. 截屏](#14) * [14.1 当前时间截图](#14.1) * [14.2 指定时间截图](#14.2) * [14.3 生成预览视图, 大约20张](#14.3) #### [15. 导出视频或GIF](#15) * [15.1 导出视频](#15.1) * [15.2 导出GIF](#15.2) * [15.3 取消操作](#15.3) #### [16. 滚动相关](#16) * [16.1 是否在 UICollectionView 或者 UITableView 中播放](#16.1) * [16.2 是否滚动显示](#16.2) * [16.3 播放器视图将要滚动显示和消失的回调](#16.3) #### [17. 自动播放 - 在 UICollectionView 或者 UITableView 中](#17) * [17.1 开启](#17.1) * [17.2 配置](#17.2) * [17.3 关闭](#17.3) * [17.4 主动调用播放下一个资源](#17.4) #### [18. 控制层数据源, 每个方法介绍](#18) * [18.1 - (UIView *)controlView;](#18.1) * [18.2 - (void)installedControlViewToVideoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer;](#18.2) #### [19. 控制层代理, 每个方法介绍](#19) * [19.1 - (void)controlLayerNeedAppear:(__kindof SJBaseVideoPlayer *)videoPlayer;](#19.1) * [19.2 - (void)controlLayerNeedDisappear:(__kindof SJBaseVideoPlayer *)videoPlayer;](#19.2) * [19.3 - (BOOL)controlLayerOfVideoPlayerCanAutomaticallyDisappear:(__kindof SJBaseVideoPlayer *)videoPlayer;](#19.3) * [19.4 - (void)videoPlayerWillAppearInScrollView:(__kindof SJBaseVideoPlayer *)videoPlayer;](#19.4) * [19.5 - (void)videoPlayerWillDisappearInScrollView:(__kindof SJBaseVideoPlayer *)videoPlayer;](#19.5) * [SJPlayStatusControlDelegate](#SJPlayStatusControlDelegate) * [19.6 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer prepareToPlay:(SJVideoPlayerURLAsset *)asset;](#19.6) * [19.7 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer statusDidChanged:(SJVideoPlayerPlayStatus)status;](#19.7) * [19.8 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayercurrentTime:(NSTimeInterval)currentTime currentTimeStr:(NSString *)currentTimeStr totalTime:(NSTimeInterval)totalTime totalTimeStr:(NSString *)totalTimeStr;](#19.8) * [19.9 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer presentationSize:(CGSize)size;](#19.9) * [SJVolumeBrightnessRateControlDelegate](#SJVolumeBrightnessRateControlDelegate) * [19.10 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer muteChanged:(BOOL)mute;](#19.10) * [19.11 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer volumeChanged:(float)volume;](#19.11) * [19.12 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer brightnessChanged:(float)brightness;](#19.12) * [19.13 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer rateChanged:(float)rate;](#19.13) * [SJBufferControlDelegate](#SJBufferControlDelegate) * [19.14 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer bufferTimeDidChange:(NSTimeInterval)bufferTime;](#19.14 ) * [19.15 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer bufferStatusDidChange:(SJPlayerBufferStatus)bufferStatus;](#19.15) * [SJRotationControlDelegate](#SJRotationControlDelegate) * [19.16 - (BOOL)canTriggerRotationOfVideoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer;](#19.16) * [19.17 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer willRotateView:(BOOL)isFull;](#19.17) * [19.18 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer didEndRotation:(BOOL)isFull;](#19.18) * [SJFitOnScreenControlDelegate](#SJFitOnScreenControlDelegate) * [19.22 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer willFitOnScreen:(BOOL)isFitOnScreen;](#19.22) * [19.23 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer didCompleteFitOnScreen:(BOOL)isFitOnScreen;](#19.23) * [SJGestureControlDelegate](#SJGestureControlDelegate) * [19.24 - (BOOL)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer gestureRecognizerShouldTrigger:(SJPlayerGestureType)type location:(CGPoint)location;](#19.24) * [19.25 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer panGestureTriggeredInTheHorizontalDirection:(SJPanGestureRecognizerState)state progressTime:(NSTimeInterval)progressTime;](#19.25) * [SJNetworkStatusControlDelegate](#SJNetworkStatusControlDelegate) * [19.26 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer reachabilityChanged:(SJNetworkStatus)status;](#19.26) * [SJLockScreenStateControlDelegate](#SJLockScreenStateControlDelegate) * [19.27 - (void)tappedPlayerOnTheLockedState:(__kindof SJBaseVideoPlayer *)videoPlayer;](#19.27) * [19.28 - (void)lockedVideoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer;](#19.28) * [19.29 - (void)unlockedVideoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer;](#19.29) * [SJSwitchVideoDefinitionControlDelegate](#SJSwitchVideoDefinitionControlDelegate) * [19.30 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer switchVideoDefinitionByURL:(NSURL *)URL statusDidChange:(SJMediaPlaybackSwitchDefinitionStatus)status;](#19.30) ___
SJBaseVideoPlayer 播放的视频资源是通过 SJVideoPlayerURLAsset 进行初始化的. SJVideoPlayerURLAsset 由两部分组成: - 视图层次 (SJPlayModel) - 资源地址 (可以是本地资源/URL/AVAsset) 默认情况下, 创建了 SJVideoPlayerURLAsset , 赋值给播放器后即可播放. 如下示例:
```Objective-C SJVideoPlayerURLAsset *asset = [[SJVideoPlayerURLAsset alloc] initWithURL:URL playModel:playModel]; _player.URLAsset = asset; ```我们先来看 SJPlayModel, 我将以下视图层次封装到了 SJPlayModel 中, 使用它初始化对应层次即可.
SJBaseVideoPlayer 播放的视频资源是通过 SJVideoPlayerURLAsset 进行初始化的. SJVideoPlayerURLAsset 由两部分组成: - 视图层次 (第一部分中的SJPlayModel) - 资源地址 (可以是本地资源/URL/AVAsset) 默认情况下, 创建了 SJVideoPlayerURLAsset , 赋值给播放器后即可播放. 如下示例:
```Objective-C SJVideoPlayerURLAsset *asset = [[SJVideoPlayerURLAsset alloc] initWithURL:URL playModel:playModel]; _player.URLAsset = asset; ```在播放时, 我们可能需要切换界面, 而希望视频能够在下一个界面无缝的进行播放. 针对此种情况 SJVideoPlayerURLAsset 提供了便利的初始化方法. 请看片段:
```Objective-C /// otherAsset即为上一个页面播放的Asset /// 除了需要一个otherAsset, 其他方面同以上的示例一模一样 _player.URLAsset = [[SJVideoPlayerURLAsset alloc] initWithOtherAsset:otherAsset playModel:playModel]; ```我们有时候想存储某个视频的播放记录, 以便下次, 能够从指定的位置进行播放. 那什么时候存储合适呢? 最好的时机就是资源被释放时. SJBaseVideoPlayer 提供了每个资源在 Dealloc 时的回调, 如下:
```Objective-C // 每个资源dealloc时的回调 _player.assetDeallocExeBlock = ^(__kindof SJBaseVideoPlayer * _Nonnull videoPlayer) { // ..... }; ``` ___播放控制: 对播放进行的操作. 此部分的内容由 "id <SJMediaPlaybackController> playbackController" 提供支持. 大多数对播放进行的操作, 均在协议 SJMediaPlaybackController 进行了声明. 正常来说实现了此协议的任何对象, 均可赋值给 player.playbackController 来替换原始实现.
播放状态有两个状态需要注意一下, 分别是 暂停和不活跃状态 当状态为暂停时, 目前有3种可能: - 正在缓冲 - 主动暂停 - 正在跳转 当状态为不活跃时, 目前有2种可能: - 播放完毕 - 播放失败
```Objective-C /** 当前播放的状态 - SJVideoPlayerPlayStatusUnknown: 未播放任何资源时的状态 - SJVideoPlayerPlayStatusPrepare: 准备播放一个资源 - SJVideoPlayerPlayStatusReadyToPlay: 准备就绪, 可以播放 - SJVideoPlayerPlayStatusPlaying: 播放中 - SJVideoPlayerPlayStatusPaused: 暂停状态, 请通过`SJVideoPlayerPausedReason`, 查看暂停原因 - SJVideoPlayerPlayStatusInactivity: 不活跃状态, 请通过`SJVideoPlayerInactivityReason`, 查看暂停原因 */ typedef NS_ENUM(NSUInteger, SJVideoPlayerPlayStatus) { SJVideoPlayerPlayStatusUnknown, SJVideoPlayerPlayStatusPrepare, SJVideoPlayerPlayStatusReadyToPlay, SJVideoPlayerPlayStatusPlaying, SJVideoPlayerPlayStatusPaused, SJVideoPlayerPlayStatusInactivity, }; ```对播放状态的判断我添加了一个便利的分类 `SJBaseVideoPlayer (PlayStatus)` 如需判断状态, 可导入头文件 `#import "SJBaseVideoPlayer+PlayStatus.h"` 使用.
```Objective-C /// 播放状态改变的回调 _player.playStatusDidChangeExeBlock = ^(__kindof SJBaseVideoPlayer * _Nonnull videoPlayer) { }; /// 对播放状态的判断我添加了一个便利的分类 @interface SJBaseVideoPlayer (PlayStatus) - (NSString *)getPlayStatusStr:(SJVideoPlayerPlayStatus)status; - (BOOL)playStatus_isUnknown; - (BOOL)playStatus_isPrepare; - (BOOL)playStatus_isReadyToPlay; - (BOOL)playStatus_isPlaying; - (BOOL)playStatus_isPaused; - (BOOL)playStatus_isPaused_ReasonBuffering; - (BOOL)playStatus_isPaused_ReasonPause; - (BOOL)playStatus_isPaused_ReasonSeeking; - (BOOL)playStatus_isInactivity; - (BOOL)playStatus_isInactivity_ReasonPlayEnd; - (BOOL)playStatus_isInactivity_ReasonPlayFailed; @end ```在播放一个资源时, 可能有一些意外情况导致播放失败(如网络环境差). 此时当用户点击刷新按钮, 我们需要对当前的资源(Asset)进行刷新. SJBaseVideoPlayer提供了直接的方法去刷新, 不需要开发者再重复的去创建新的Asset.
```Objective-C [_player refresh]; ```关于后台播放视频, 引用自: https://juejin.im/post/5a38e1a0f265da4327185a26 当您想在后台播放视频时: 1. 需要设置 videoPlayer.pauseWhenAppDidEnterBackground = NO; (该值默认为YES, 即App进入后台默认暂停). 2. 前往 `TARGETS` -> `Capability` -> enable `Background Modes` -> select this mode `Audio, AirPlay, and Picture in Picture`
```Objective-C _player.pauseWhenAppDidEnterBackground = NO; // 默认值为 YES, 即进入后台后 暂停. ```注意, 调用此方法后, 当前的 asset 将会被清空. 也就是说, 调用 play等播放操作将会无效.
```Objective-C [_player stop]; ```从头开始重新播放
```Objective-C [_player replay]; ```某些时候, 我们需要接入第三方的视频SDK, 但是又想使用 SJBaseVideoPlayer 封装的其他的功能. 这个时候, 我们可以自己动手, 将第三方的SDK封装一下, 实现 SJMediaPlaybackController 协议, 管理 SJBaseVideoPlayer 中的播放操作. 示例: - 可以参考 SJAVMediaPlaybackController 中的实现. - 封装 ijkplayer 的示例: https://gitee.com/changsanjiang/SJIJKMediaPlaybackController
```Objective-C _player.playbackController = Your PlaybackController. ``` ___控制层的显示和隐藏, 此部分的内容由 "id <SJControlLayerAppearManager> controlLayerAppearManager" 提供支持. controlLayerAppearManager 内部存在一个定时器, 当控制层显示时, 会开启此定时器. 一定间隔后, 会尝试隐藏控制层. 其他相关操作, 请见以下内容.
当控制层需要显示时, 可以调用下面方法. 此方法将会回调控制层的代理方法: "- (void)controlLayerNeedAppear:(__kindof SJBaseVideoPlayer *)videoPlayer;" 代理将会对当前的控制层进行显示处理.
```Objective-C [_player controlLayerNeedAppear]; ```当控制层需要隐藏时, 可以调用下面方法. 此方法将会回调控制层的代理方法: "- (void)controlLayerNeedDisappear:(__kindof SJBaseVideoPlayer *)videoPlayer;" 代理将会对当前的控制层进行隐藏处理.
```Objective-C [_player controlLayerNeedDisappear]; ```有时候, 我们可能不需要对控制层的显示和隐藏进行管理. 这个时候可以设置如下属性, 来禁止管理类的操作.
```Objective-C @property (nonatomic) BOOL disabledControlLayerAppearManager; // default value is NO. ```同样的, 协议 "SJControlLayerAppearManager" 定义了一系列的操作, 只要实现了这些协议方法的对象, 就可以管理控制层的显示和隐藏.
```Objective-C _player.controlLayerAppearManager = Your controlLayerAppearManager; ``` ___设备亮度和音量的调整, 此部分的内容由 "id <SJDeviceVolumeAndBrightnessManager> deviceVolumeAndBrightnessManager" 提供支持.
当需要对设备音量视图进行自定义时, 可以自己动手撸一个 SJDeviceVolumeAndBrightnessManager.
```Objective-C _player.deviceVolumeAndBrightnessManager = Your deviceVolumeAndBrightnessManager; ``` ___此部分的内容由 "id <SJRotationManagerProtocol> rotationManager" 提供支持. 对于旋转, 我们开发者肯定需要绝对的控制, 例如: 设置自动旋转所支持方向. 能够主动+自动旋转, 而且还需要能在适当的时候禁止自动旋转. 旋转前后的回调等等... 放心这些功能都有, 我挨个给大家介绍. 另外旋转有两种方式: - 仅旋转播放器视图 (默认情况下) - 使 ViewController 也一起旋转 具体请看下面介绍.
先说说何为自动旋转. 其实就是当设备方向变更时, 播放器根据设备方向进行自动旋转.
这里有两点需要注意: - 合适的时候要记得恢复自动旋转. - 禁止自动旋转后, 主动调用旋转, 还是可以旋转的.
```Objective-C _player.disableAutoRotation = YES; ```主动旋转. 当我们想主动旋转时, 大概分为以下三点: - 播放器旋转到用户当前的设备方向或恢复小屏. - 主动旋转到指定方向. - 主动旋转完成后的回调. 请看以下方法, 分别对应以上三点:
```Objective-C - (void)rotate; - (void)rotate:(SJOrientation)orientation animated:(BOOL)animated; - (void)rotate:(SJOrientation)orientation animated:(BOOL)animated completion:(void (^ _Nullable)(__kindof SJBaseVideoPlayer *player))block; ```直接全屏, 或者说充满屏幕, 但不旋转.
此部分内容由 id<SJFlipTransitionManager> flipTransitionManager 提供支持 目前镜像翻转只写了 水平翻转, 未来可能会加入更多的翻转类型.
```Objective-C typedef enum : NSUInteger { SJViewFlipTransition_Identity, SJViewFlipTransition_Horizontally, // 水平翻转 } SJViewFlipTransition; ```该部分管理类的协议定义在 SJFlipTransitionManagerProtocol 中, 实现该协议的任何对象, 均可赋值给播放器, 替换原始实现.
___此部分内容由 id<SJReachability> reachability 提供支持 默认的 reachability 是个单例, 在App生命周期中, 仅创建一次. 因此每个播放器对象持有的 reachability 都是相同的.
该部分管理类的协议定义在 SJNetworkStatus 中, 实现该协议的任何对象, 均可赋值给播放器, 替换原始实现.
___此部分内容由 id<SJPlayerGestureControl> gestureControl 提供支持 播放器默认存在四种手势, 每个手势触发的回调均定义在 SJPlayerGestureControl 中, 当想改变某个手势的处理时, 可以直接修改对应手势触发的 block 即可. 具体请看以下部分.
双击会触发暂停或播放的操作
```Objective-C __weak typeof(self) _self = self; _gestureControl.doubleTapHandler = ^(id当用户做放大或收缩触发该手势时, 会设置播放器显示模式`Aspect`或`AspectFill`.
```Objective-C __weak typeof(self) _self = self; _gestureControl.pinchHandler = ^(id当需要禁止某个手势时, 可以像如下设置:
```Objective-C /// 此处为禁止单击和双击手势 _player.disabledGestures = SJPlayerGestureType_SingleTap | SJPlayerGestureType_DoubleTap; typedef enum : NSUInteger { SJPlayerGestureType_SingleTap, SJPlayerGestureType_DoubleTap, SJPlayerGestureType_Pan, SJPlayerGestureType_Pinch, } SJPlayerGestureType; ```该部分管理类的协议定义在 SJPlayerGestureControlProtocol 中, 实现该协议的任何对象, 均可赋值给播放器, 替换原始实现.
___资源在初始化时, 由于暂时没有画面可以呈现, 会出现短暂的黑屏. 在此期间, 建议大家设置一下占位图.
目前提示文本支持 NSString 以及 NSAttributedString.
接入播放器的 ViewController 中, 会写一些固定的代码, 我将这些固定代码(例如 进入下个页面时, 需要当前页面的播放器暂停), 都封装在了以下方法中. ```Objective-C - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [_player vc_viewDidAppear]; } ``` 在适当的时候直接调用即可, 以下为内部实现:
当 ViewController 的 viewDidAppear 调用时, 恢复播放 实现如下:
```Objective-C - (void)vc_viewDidAppear { if ( !self.isPlayOnScrollView || (self.isPlayOnScrollView && self.isScrollAppeared) ) { /// 恢复播放 [self play]; } /// 标识vc已显示 /// vc_isDisappeared 是自动旋转触发的条件之一, 如果控制器 disappear 了, 就不会触发旋转 self.vc_isDisappeared = NO; } ```当 ViewController 的 viewWillDisappear 调用时, 设置标识为YES 实现如下:
```Objective-C - (void)vc_viewWillDisappear { /// 标识vc已显示 /// vc_isDisappeared 是自动旋转触发的条件之一, 如果控制器 disappear 了, 就不会触发旋转 self.vc_isDisappeared = YES; } ```当 ViewController 的 viewDidDisappear 调用时, 暂停播放 实现如下:
```Objective-C - (void)vc_viewDidDisappear { [self pause]; } ```状态栏是否可以隐藏 实现如下:
```Objective-C - (BOOL)vc_prefersStatusBarHidden { if ( _tmpShowStatusBar ) return NO; // 临时显示 if ( _tmpHiddenStatusBar ) return YES; // 临时隐藏 if ( self.lockedScreen ) return YES; // 锁屏时, 不显示 if ( self.rotationManager.isTransitioning ) { // 旋转时, 不显示 if ( !self.disabledControlLayerAppearManager && self.controlLayerIsAppeared ) return NO; return YES; } // 全屏播放时, 使状态栏根据控制层显示或隐藏 if ( self.isFullScreen ) return !self.controlLayerIsAppeared; return NO; } ```状态栏显示白色还是黑色 实现如下:
```Objective-C - (UIStatusBarStyle)vc_preferredStatusBarStyle { // 全屏播放时, 使状态栏变成白色 if ( self.isFullScreen || self.fitOnScreen ) return UIStatusBarStyleLightContent; return UIStatusBarStyleDefault; } ```有时候, 可能会希望临时显示状态栏, 例如全屏转回小屏时, 旋转之前, 需要将状态栏显示.
```Objective-C [_player needShowStatusBar]; ```有时候, 可能会希望临时隐藏状态栏, 例如某个播放器控制层不需要显示状态栏.
```Objective-C [_player needHiddenStatusBar]; ``` ___此部分的内容由 SJPlayModelPropertiesObserver 提供支持.
目前支持在 UICollectionViewCell 和 UITableViewCell 中自动播放. 使用之前, 请导入头文件 `#import "UIScrollView+ListViewAutoplaySJAdd.h"`
controlView 为控制层的视图, 它将会被添加到播放器中