ZFPlayerMediaPlayback
1
2
3
4
5
6
7
8
@property (nonatomic) ZFPlayerView *view;
- (void)prepareToPlay;
- (void)reloadPlayer;
- (void)pause;
- (void)replay;
- (void)stop;
/// Use this method to seek to a specified time for the current player and to be notified when the seek operation is complete.
- (void)seekToTime:(NSTimeInterval)time completionHandler:(void (^ __nullable)(BOOL finished))completionHandler;
ZFPlayerView
1
2
3
4
5
6
7
8
/// player content view.
@property (nonatomic, strong) UIView *playerView;
/// The video size.
@property (nonatomic, assign) CGSize presentationSize;
/// Determines how the content scales to fit the view.
@property (nonatomic, assign) ZFPlayerScalingMode scalingMode;
/// The cover for playerView.
@property (nonatomic, strong, readonly) UIImageView *coverImageView;
ZFPlayerController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
@property (nonatomic, weak) UIScrollView *scrollView;
@property (nonatomic, strong) ZFPlayerNotification *notification;
@property (nonatomic, strong) UISlider *volumeViewSlider;
@property (nonatomic, assign) NSInteger containerViewTag;
@property (nonatomic, assign) ZFPlayerContainerType containerType;
@property (nonatomic, strong) UIView *containerView;
/// The currentPlayerManager must conform `ZFPlayerMediaPlayback` protocol.
@property (nonatomic, strong) id<ZFPlayerMediaPlayback> currentPlayerManager;
/// The custom controlView must conform `ZFPlayerMediaControl` protocol.
@property (nonatomic, strong) UIView<ZFPlayerMediaControl> *controlView;
/// The notification manager class.
@property (nonatomic, strong, readonly) ZFPlayerNotification *notification;
/// The container view type.
@property (nonatomic, assign, readonly) ZFPlayerContainerType containerType;
/// The player's small container view.
@property (nonatomic, strong, readonly) ZFFloatView *smallFloatView;
/// Whether the small window is displayed.
@property (nonatomic, assign, readonly) BOOL isSmallFloatViewShow;
- (void)setScrollView:(UIScrollView *)scrollView {
objc_setAssociatedObject(self, @selector(scrollView), scrollView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
@zf_weakify(self)
scrollView.zf_playerWillAppearInScrollView = ^(NSIndexPath * _Nonnull indexPath) {
@zf_strongify(self)
if (self.isFullScreen) return;
if (self.zf_playerWillAppearInScrollView) self.zf_playerWillAppearInScrollView(indexPath);
if ([self.controlView respondsToSelector:@selector(playerDidAppearInScrollView:)]) {
[self.controlView playerDidAppearInScrollView:self];
}
};
...
}
- (void)setContainerViewTag:(NSInteger)containerViewTag {
objc_setAssociatedObject(self, @selector(containerViewTag), @(containerViewTag), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
self.scrollView.zf_containerViewTag = containerViewTag;
}
- (void)setContainerView:(UIView *)containerView {
_containerView = containerView;
if (self.scrollView) {
self.scrollView.zf_containerView = containerView;
}
if (!containerView) return;
containerView.userInteractionEnabled = YES;
[self layoutPlayerSubViews];
[self.orientationObserver updateRotateView:self.currentPlayerManager.view containerView:containerView];
}
- (void)setControlView:(UIView<ZFPlayerMediaControl> *)controlView {
if (controlView && controlView != _controlView) {
[_controlView removeFromSuperview];
}
_controlView = controlView;
if (!controlView) return;
controlView.player = self;
[self layoutPlayerSubViews];
}
- (void)setCurrentPlayerManager:(id<ZFPlayerMediaPlayback>)currentPlayerManager {
if (!currentPlayerManager) return;
if (_currentPlayerManager.isPreparedToPlay) {
[_currentPlayerManager stop];
[_currentPlayerManager.view removeFromSuperview];
[self removeDeviceOrientationObserver];
[self.gestureControl removeGestureToView:self.currentPlayerManager.view];
}
_currentPlayerManager = currentPlayerManager;
self.gestureControl.disableTypes = self.disableGestureTypes;
[self.gestureControl addGestureToView:currentPlayerManager.view];
[self playerManagerCallbcak];
self.controlView.player = self;
[self layoutPlayerSubViews];
if (currentPlayerManager.isPreparedToPlay) {
[self addDeviceOrientationObserver];
}
[self.orientationObserver updateRotateView:currentPlayerManager.view containerView:self.containerView];
}
- (void)layoutPlayerSubViews {
if (self.containerView && self.currentPlayerManager.view && self.currentPlayerManager.isPreparedToPlay) {
UIView *superview = nil;
if (self.isFullScreen) {
superview = self.orientationObserver.fullScreenContainerView;
} else if (self.containerView) {
superview = self.containerView;
}
[superview addSubview:self.currentPlayerManager.view];
[self.currentPlayerManager.view addSubview:self.controlView];
self.currentPlayerManager.view.frame = superview.bounds;
self.currentPlayerManager.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.controlView.frame = self.currentPlayerManager.view.bounds;
self.controlView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.orientationObserver updateRotateView:self.currentPlayerManager.view containerView:self.containerView];
}
}
- (void)setPlayingIndexPath:(NSIndexPath *)playingIndexPath {
objc_setAssociatedObject(self, @selector(playingIndexPath), playingIndexPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
if (playingIndexPath) {
self.isSmallFloatViewShow = NO;
if (self.smallFloatView) self.smallFloatView.hidden = YES;
UIView *cell = [self.scrollView zf_getCellForIndexPath:playingIndexPath];
self.containerView = [cell viewWithTag:self.containerViewTag]; // 从cell找到并set `containerView`
[self.orientationObserver updateRotateView:self.currentPlayerManager.view rotateViewAtCell:cell playerViewTag:self.containerViewTag];
[self addDeviceOrientationObserver];
self.scrollView.zf_playingIndexPath = playingIndexPath;
[self layoutPlayerSubViews];
} else {
self.scrollView.zf_playingIndexPath = playingIndexPath;
}
UIScrollView+ZFPlayer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
- (void)_scrollViewDidStopScroll {
self.zf_scrollDirection = ZFPlayerScrollDirectionNone;
@zf_weakify(self)
[self zf_filterShouldPlayCellWhileScrolled:^(NSIndexPath * _Nonnull indexPath) {
@zf_strongify(self)
if (self.zf_scrollViewDidStopScrollCallback) self.zf_scrollViewDidStopScrollCallback(indexPath);
if (self.zf_scrollViewDidEndScrollingCallback) self.zf_scrollViewDidEndScrollingCallback(indexPath);
}];
}
- (void)_scrollViewBeginDragging {
if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionVertical) {
self.zf_lastOffsetY = self.contentOffset.y;
} else {
self.zf_lastOffsetX = self.contentOffset.x;
}
}
- (void)setZf_shouldPlayIndexPath:(NSIndexPath *)zf_shouldPlayIndexPath {
if (self.zf_playerShouldPlayInScrollView) self.zf_playerShouldPlayInScrollView(zf_shouldPlayIndexPath);
if (self.zf_shouldPlayIndexPathCallback) self.zf_shouldPlayIndexPathCallback(zf_shouldPlayIndexPath);
objc_setAssociatedObject(self, @selector(zf_shouldPlayIndexPath), zf_shouldPlayIndexPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setZf_playingIndexPath:(NSIndexPath *)zf_playingIndexPath {
objc_setAssociatedObject(self, @selector(zf_playingIndexPath), zf_playingIndexPath, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
if (zf_playingIndexPath && [zf_playingIndexPath compare:self.zf_shouldPlayIndexPath] != NSOrderedSame) {
self.zf_shouldPlayIndexPath = zf_playingIndexPath;
}
}
管理试图层级
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- (void)layoutPlayerSubViews {
if (self.containerView && self.currentPlayerManager.view && self.currentPlayerManager.isPreparedToPlay) {
UIView *superview = nil;
if (self.isFullScreen) {
superview = self.orientationObserver.fullScreenContainerView;
} else if (self.containerView) {
superview = self.containerView;
}
[superview addSubview:self.currentPlayerManager.view];
[self.currentPlayerManager.view addSubview:self.controlView];
self.currentPlayerManager.view.frame = superview.bounds;
self.currentPlayerManager.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
self.controlView.frame = self.currentPlayerManager.view.bounds;
self.controlView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.orientationObserver updateRotateView:self.currentPlayerManager.view containerView:self.containerView];
}
}
1
2
3
4
5
PlayerManager持有的view(ZFPlayView), 将被添加到playerController的containerView上
controller持有的controlView(ZFPlayerMediaControl)将被添加到playerManager持有的view(ZFPlayView)上
由playerManager将视频层设置为其view(ZFPlayView)的playerView,并添加在上面
AddToCell
1
2
3
4
5
6
7
8
9
10
11
12
13
- (void)addPlayerViewToCell {
self.isSmallFloatViewShow = NO;
self.smallFloatView.hidden = YES;
UIView *cell = [self.scrollView zf_getCellForIndexPath:self.playingIndexPath];
self.containerView = [cell viewWithTag:self.containerViewTag];
[self.containerView addSubview:self.currentPlayerManager.view];
self.currentPlayerManager.view.frame = self.containerView.bounds;
self.currentPlayerManager.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.orientationObserver updateRotateView:self.currentPlayerManager.view rotateViewAtCell:cell playerViewTag:self.containerViewTag];
if ([self.controlView respondsToSelector:@selector(videoPlayer:floatViewShow:)]) {
[self.controlView videoPlayer:self floatViewShow:NO];
}
}
AddToContainer
//// Add video to the container view
- (void)addPlayerViewToContainerView:(UIView *)containerView {
self.isSmallFloatViewShow = NO;
self.smallFloatView.hidden = YES;
self.containerView = containerView;
[self.containerView addSubview:self.currentPlayerManager.view];
self.currentPlayerManager.view.frame = self.containerView.bounds;
self.currentPlayerManager.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.orientationObserver updateRotateView:self.currentPlayerManager.view containerView:self.containerView];
if ([self.controlView respondsToSelector:@selector(videoPlayer:floatViewShow:)]) {
[self.controlView videoPlayer:self floatViewShow:NO];
}
}
AddToSmallFloatView
1
2
3
4
5
6
7
8
9
10
11
- (void)addPlayerViewToSmallFloatView {
self.isSmallFloatViewShow = YES;
self.smallFloatView.hidden = NO;
[self.smallFloatView addSubview:self.currentPlayerManager.view];
self.currentPlayerManager.view.frame = self.smallFloatView.bounds;
self.currentPlayerManager.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.orientationObserver updateRotateView:self.currentPlayerManager.view containerView:self.smallFloatView];
if ([self.controlView respondsToSelector:@selector(videoPlayer:floatViewShow:)]) {
[self.controlView videoPlayer:self floatViewShow:YES];
}
}
播放控制
PlayNext
1
2
3
4
5
6
7
8
9
- (void)playTheNext {
if (self.assetURLs.count > 0) {
NSInteger index = self.currentPlayIndex + 1;
if (index >= self.assetURLs.count) return;
NSURL *assetURL = [self.assetURLs objectAtIndex:index];
self.assetURL = assetURL;
self.currentPlayIndex = [self.assetURLs indexOfObject:assetURL];
}
}
PlayPrevious
1
2
3
4
5
6
7
8
9
- (void)playThePrevious {
if (self.assetURLs.count > 0) {
NSInteger index = self.currentPlayIndex - 1;
if (index < 0) return;
NSURL *assetURL = [self.assetURLs objectAtIndex:index];
self.assetURL = assetURL;
self.currentPlayIndex = [self.assetURLs indexOfObject:assetURL];
}
}
Play Specific at index of a list
1
2
3
4
5
6
7
8
- (void)playTheIndex:(NSInteger)index {
if (self.assetURLs.count > 0) {
if (index >= self.assetURLs.count) return;
NSURL *assetURL = [self.assetURLs objectAtIndex:index];
self.assetURL = assetURL;
self.currentPlayIndex = index;
}
}
停止播放
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)stop {
if (self.isFullScreen && self.exitFullScreenWhenStop) {
@zf_weakify(self)
[self.orientationObserver enterFullScreen:NO animated:NO completion:^{
@zf_strongify(self)
[self.currentPlayerManager stop];
[self.currentPlayerManager.view removeFromSuperview];
}];
} else {
[self.currentPlayerManager stop];
[self.currentPlayerManager.view removeFromSuperview];
}
if (self.scrollView) self.scrollView.zf_stopPlay = YES;
[self.notification removeNotification];
[self.orientationObserver removeDeviceOrientationObserver];
}
停止当前Cell播放
1
2
3
4
5
6
7
8
- (void)stopCurrentPlayingCell {
if (self.scrollView.zf_playingIndexPath) {
[self stop];
self.isSmallFloatViewShow = NO;
self.playingIndexPath = nil;
if (self.smallFloatView) self.smallFloatView.hidden = YES;
}
}
停止container播放
1
2
3
4
5
6
7
- (void)stopCurrentPlayingView {
if (self.containerView) {
[self stop];
self.isSmallFloatViewShow = NO;
if (self.smallFloatView) self.smallFloatView.hidden = YES;
}
}
亮度及声音控制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
- (float)brightness {
return [UIScreen mainScreen].brightness;
}
- (float)volume {
CGFloat volume = self.volumeViewSlider.value;
if (volume == 0) {
volume = [[AVAudioSession sharedInstance] outputVolume];
}
return volume;
}
- (BOOL)isMuted {
return self.volume == 0;
}
- (void)setVolume:(float)volume {
volume = MIN(MAX(0, volume), 1);
objc_setAssociatedObject(self, @selector(volume), @(volume), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
self.volumeViewSlider.value = volume;
}
- (void)setMuted:(BOOL)muted {
if (muted) {
if (self.volumeViewSlider.value > 0) {
self.lastVolumeValue = self.volumeViewSlider.value;
}
self.volumeViewSlider.value = 0;
} else {
self.volumeViewSlider.value = self.lastVolumeValue;
}
}
- (void)setLastVolumeValue:(float)lastVolumeValue {
objc_setAssociatedObject(self, @selector(lastVolumeValue), @(lastVolumeValue), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setBrightness:(float)brightness {
brightness = MIN(MAX(0, brightness), 1);
objc_setAssociatedObject(self, @selector(brightness), @(brightness), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[UIScreen mainScreen].brightness = brightness;
}
播放时间控制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
- (NSTimeInterval)currentTime {
return self.currentPlayerManager.currentTime;
}
- (NSTimeInterval)totalTime {
return self.currentPlayerManager.totalTime;
}
- (NSTimeInterval)bufferTime {
return self.currentPlayerManager.bufferTime;
}
- (float)progress {
if (self.totalTime == 0) return 0;
return self.currentTime/self.totalTime;
}
- (float)bufferProgress {
if (self.totalTime == 0) return 0;
return self.bufferTime/self.totalTime;
}
- (void)seekToTime:(NSTimeInterval)time completionHandler:(void (^)(BOOL))completionHandler {
[self.currentPlayerManager seekToTime:time completionHandler:completionHandler];
}
生命周期控制
1
scroll 滑动控制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
- (void)setPlayerDisapperaPercent:(CGFloat)playerDisapperaPercent {
playerDisapperaPercent = MIN(MAX(0.0, playerDisapperaPercent), 1.0);
self.scrollView.zf_playerDisapperaPercent = playerDisapperaPercent;
objc_setAssociatedObject(self, @selector(playerDisapperaPercent), @(playerDisapperaPercent), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setPlayerApperaPercent:(CGFloat)playerApperaPercent {
playerApperaPercent = MIN(MAX(0.0, playerApperaPercent), 1.0);
self.scrollView.zf_playerApperaPercent = playerApperaPercent;
objc_setAssociatedObject(self, @selector(playerApperaPercent), @(playerApperaPercent), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setZf_playerAppearingInScrollView:(void (^)(NSIndexPath * _Nonnull, CGFloat))zf_playerAppearingInScrollView {
objc_setAssociatedObject(self, @selector(zf_playerAppearingInScrollView), zf_playerAppearingInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void)setZf_playerDisappearingInScrollView:(void (^)(NSIndexPath * _Nonnull, CGFloat))zf_playerDisappearingInScrollView {
objc_setAssociatedObject(self, @selector(zf_playerDisappearingInScrollView), zf_playerDisappearingInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void)setZf_playerDidAppearInScrollView:(void (^)(NSIndexPath * _Nonnull))zf_playerDidAppearInScrollView {
objc_setAssociatedObject(self, @selector(zf_playerDidAppearInScrollView), zf_playerDidAppearInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void)setZf_playerWillDisappearInScrollView:(void (^)(NSIndexPath * _Nonnull))zf_playerWillDisappearInScrollView {
objc_setAssociatedObject(self, @selector(zf_playerWillDisappearInScrollView), zf_playerWillDisappearInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void)setZf_playerWillAppearInScrollView:(void (^)(NSIndexPath * _Nonnull))zf_playerWillAppearInScrollView {
objc_setAssociatedObject(self, @selector(zf_playerWillAppearInScrollView), zf_playerWillAppearInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void)setZf_playerDidDisappearInScrollView:(void (^)(NSIndexPath * _Nonnull))zf_playerDidDisappearInScrollView {
objc_setAssociatedObject(self, @selector(zf_playerDidDisappearInScrollView), zf_playerDidDisappearInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void)setZf_playerShouldPlayInScrollView:(void (^)(NSIndexPath * _Nonnull))zf_playerShouldPlayInScrollView {
objc_setAssociatedObject(self, @selector(zf_playerShouldPlayInScrollView), zf_playerShouldPlayInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (void)setZf_scrollViewDidEndScrollingCallback:(void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidEndScrollingCallback {
objc_setAssociatedObject(self, @selector(zf_scrollViewDidEndScrollingCallback), zf_scrollViewDidEndScrollingCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
手势控制
class
ZFPlayerGestureControl
class
ZFPlayerController (ZFPlayerViewGesture)
@property (nonatomic, readonly) ZFPlayerGestureControl *gestureControl;
/// The gesture types that the player not support.
@property (nonatomic, assign) ZFPlayerDisableGestureTypes disableGestureTypes;
/// The pan gesture moving direction that the player not support.
@property (nonatomic) ZFPlayerDisablePanMovingDirection disablePanMovingDirection;
横竖屏控制
class
ZFOrientationObserver
通知管理
class
ZFPlayerNotification
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@property (nonatomic, readonly) ZFPlayerBackgroundState backgroundState;
@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);
@property (nonatomic, copy, nullable) void(^categoryChange)(ZFPlayerNotification *registrar);
@property (nonatomic, copy, nullable) void(^volumeChanged)(float volume);
@property (nonatomic, copy, nullable) void(^audioInterruptionCallback)(AVAudioSessionInterruptionType interruptionType);
- (void)addNotification;
- (void)removeNotification;
PlayerManager.view -> ZFPlayerView
PlayerManager.view.playerView -> PlayerManager.Player.View
ContainerView -> ZFPlayerview(PlayerManager.View) -> PlayerControlView, playerView(PlayerManager.Player.View)
1
[options setOptionIntValue:1 forKey:@"videotoolbox" ofCategory:kIJKFFOptionCategoryPlayer];