initial
44
Pods/ZFPlayer/ZFPlayer/Classes/AVPlayer/ZFAVPlayerManager.h
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// ZFAVPlayerManager.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#if __has_include(<ZFPlayer/ZFPlayerMediaPlayback.h>)
|
||||
#import <ZFPlayer/ZFPlayerMediaPlayback.h>
|
||||
#else
|
||||
#import "ZFPlayerMediaPlayback.h"
|
||||
#endif
|
||||
|
||||
@interface ZFAVPlayerManager : NSObject <ZFPlayerMediaPlayback>
|
||||
|
||||
@property (nonatomic, strong, readonly) AVURLAsset *asset;
|
||||
@property (nonatomic, strong, readonly) AVPlayerItem *playerItem;
|
||||
@property (nonatomic, strong, readonly) AVPlayer *player;
|
||||
@property (nonatomic, assign) NSTimeInterval timeRefreshInterval;
|
||||
/// 视频请求头
|
||||
@property (nonatomic, strong) NSDictionary *requestHeader;
|
||||
|
||||
@property (nonatomic, strong, readonly) AVPlayerLayer *avPlayerLayer;
|
||||
|
||||
@end
|
||||
527
Pods/ZFPlayer/ZFPlayer/Classes/AVPlayer/ZFAVPlayerManager.m
generated
Normal file
@@ -0,0 +1,527 @@
|
||||
//
|
||||
// ZFAVPlayerManager.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFAVPlayerManager.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
#if __has_include(<ZFPlayer/ZFPlayer.h>)
|
||||
#import <ZFPlayer/ZFKVOController.h>
|
||||
#import <ZFPlayer/ZFPlayerConst.h>
|
||||
#import <ZFPlayer/ZFReachabilityManager.h>
|
||||
#else
|
||||
#import "ZFKVOController.h"
|
||||
#import "ZFPlayerConst.h"
|
||||
#import "ZFReachabilityManager.h"
|
||||
#endif
|
||||
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
|
||||
|
||||
/*!
|
||||
* Refresh interval for timed observations of AVPlayer
|
||||
*/
|
||||
static NSString *const kStatus = @"status";
|
||||
static NSString *const kLoadedTimeRanges = @"loadedTimeRanges";
|
||||
static NSString *const kPlaybackBufferEmpty = @"playbackBufferEmpty";
|
||||
static NSString *const kPlaybackLikelyToKeepUp = @"playbackLikelyToKeepUp";
|
||||
static NSString *const kPresentationSize = @"presentationSize";
|
||||
|
||||
@interface ZFPlayerPresentView : UIView
|
||||
|
||||
@property (nonatomic, strong) AVPlayer *player;
|
||||
/// default is AVLayerVideoGravityResizeAspect.
|
||||
@property (nonatomic, strong) AVLayerVideoGravity videoGravity;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFPlayerPresentView
|
||||
|
||||
+ (Class)layerClass {
|
||||
return [AVPlayerLayer class];
|
||||
}
|
||||
|
||||
- (AVPlayerLayer *)avLayer {
|
||||
return (AVPlayerLayer *)self.layer;
|
||||
}
|
||||
|
||||
- (void)setPlayer:(AVPlayer *)player {
|
||||
if (player == _player) return;
|
||||
self.avLayer.player = player;
|
||||
}
|
||||
|
||||
- (void)setVideoGravity:(AVLayerVideoGravity)videoGravity {
|
||||
if (videoGravity == self.videoGravity) return;
|
||||
[self avLayer].videoGravity = videoGravity;
|
||||
}
|
||||
|
||||
- (AVLayerVideoGravity)videoGravity {
|
||||
return [self avLayer].videoGravity;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFAVPlayerManager () {
|
||||
id _timeObserver;
|
||||
id _itemEndObserver;
|
||||
ZFKVOController *_playerItemKVO;
|
||||
}
|
||||
@property (nonatomic, strong) AVPlayerLayer *playerLayer;
|
||||
@property (nonatomic, assign) BOOL isBuffering;
|
||||
@property (nonatomic, assign) BOOL isReadyToPlay;
|
||||
@property (nonatomic, strong) AVAssetImageGenerator *imageGenerator;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFAVPlayerManager
|
||||
|
||||
@synthesize view = _view;
|
||||
@synthesize currentTime = _currentTime;
|
||||
@synthesize totalTime = _totalTime;
|
||||
@synthesize playerPlayTimeChanged = _playerPlayTimeChanged;
|
||||
@synthesize playerBufferTimeChanged = _playerBufferTimeChanged;
|
||||
@synthesize playerDidToEnd = _playerDidToEnd;
|
||||
@synthesize bufferTime = _bufferTime;
|
||||
@synthesize playState = _playState;
|
||||
@synthesize loadState = _loadState;
|
||||
@synthesize assetURL = _assetURL;
|
||||
@synthesize playerPrepareToPlay = _playerPrepareToPlay;
|
||||
@synthesize playerReadyToPlay = _playerReadyToPlay;
|
||||
@synthesize playerPlayStateChanged = _playerPlayStateChanged;
|
||||
@synthesize playerLoadStateChanged = _playerLoadStateChanged;
|
||||
@synthesize seekTime = _seekTime;
|
||||
@synthesize muted = _muted;
|
||||
@synthesize volume = _volume;
|
||||
@synthesize presentationSize = _presentationSize;
|
||||
@synthesize isPlaying = _isPlaying;
|
||||
@synthesize rate = _rate;
|
||||
@synthesize isPreparedToPlay = _isPreparedToPlay;
|
||||
@synthesize shouldAutoPlay = _shouldAutoPlay;
|
||||
@synthesize scalingMode = _scalingMode;
|
||||
@synthesize playerPlayFailed = _playerPlayFailed;
|
||||
@synthesize presentationSizeChanged = _presentationSizeChanged;
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_scalingMode = ZFPlayerScalingModeAspectFit;
|
||||
_shouldAutoPlay = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)prepareToPlay {
|
||||
if (!_assetURL) return;
|
||||
_isPreparedToPlay = YES;
|
||||
[self initializePlayer];
|
||||
if (self.shouldAutoPlay) {
|
||||
[self play];
|
||||
}
|
||||
self.loadState = ZFPlayerLoadStatePrepare;
|
||||
if (self.playerPrepareToPlay) self.playerPrepareToPlay(self, self.assetURL);
|
||||
}
|
||||
|
||||
- (void)reloadPlayer {
|
||||
self.seekTime = self.currentTime;
|
||||
[self prepareToPlay];
|
||||
}
|
||||
|
||||
- (void)play {
|
||||
if (!_isPreparedToPlay) {
|
||||
[self prepareToPlay];
|
||||
} else {
|
||||
[self.player play];
|
||||
self.player.rate = self.rate;
|
||||
self->_isPlaying = YES;
|
||||
self.playState = ZFPlayerPlayStatePlaying;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)pause {
|
||||
[self.player pause];
|
||||
self->_isPlaying = NO;
|
||||
self.playState = ZFPlayerPlayStatePaused;
|
||||
[_playerItem cancelPendingSeeks];
|
||||
[_asset cancelLoading];
|
||||
}
|
||||
|
||||
- (void)stop {
|
||||
[_playerItemKVO safelyRemoveAllObservers];
|
||||
self.loadState = ZFPlayerLoadStateUnknown;
|
||||
self.playState = ZFPlayerPlayStatePlayStopped;
|
||||
if (self.player.rate != 0) [self.player pause];
|
||||
[_playerItem cancelPendingSeeks];
|
||||
[_asset cancelLoading];
|
||||
[self.player removeTimeObserver:_timeObserver];
|
||||
[self.player replaceCurrentItemWithPlayerItem:nil];
|
||||
self.presentationSize = CGSizeZero;
|
||||
_timeObserver = nil;
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:_itemEndObserver name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem];
|
||||
_itemEndObserver = nil;
|
||||
_isPlaying = NO;
|
||||
_player = nil;
|
||||
_assetURL = nil;
|
||||
_playerItem = nil;
|
||||
_isPreparedToPlay = NO;
|
||||
self->_currentTime = 0;
|
||||
self->_totalTime = 0;
|
||||
self->_bufferTime = 0;
|
||||
self.isReadyToPlay = NO;
|
||||
}
|
||||
|
||||
- (void)replay {
|
||||
@zf_weakify(self)
|
||||
[self seekToTime:0 completionHandler:^(BOOL finished) {
|
||||
@zf_strongify(self)
|
||||
if (finished) {
|
||||
[self play];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)seekToTime:(NSTimeInterval)time completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
|
||||
if (self.totalTime > 0) {
|
||||
[_player.currentItem cancelPendingSeeks];
|
||||
int32_t timeScale = _player.currentItem.asset.duration.timescale;
|
||||
CMTime seekTime = CMTimeMakeWithSeconds(time, timeScale);
|
||||
[_player seekToTime:seekTime toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:completionHandler];
|
||||
} else {
|
||||
self.seekTime = time;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)thumbnailImageAtCurrentTime {
|
||||
CMTime expectedTime = self.playerItem.currentTime;
|
||||
CGImageRef cgImage = NULL;
|
||||
|
||||
self.imageGenerator.requestedTimeToleranceBefore = kCMTimeZero;
|
||||
self.imageGenerator.requestedTimeToleranceAfter = kCMTimeZero;
|
||||
cgImage = [self.imageGenerator copyCGImageAtTime:expectedTime actualTime:NULL error:NULL];
|
||||
|
||||
if (!cgImage) {
|
||||
self.imageGenerator.requestedTimeToleranceBefore = kCMTimePositiveInfinity;
|
||||
self.imageGenerator.requestedTimeToleranceAfter = kCMTimePositiveInfinity;
|
||||
cgImage = [self.imageGenerator copyCGImageAtTime:expectedTime actualTime:NULL error:NULL];
|
||||
}
|
||||
|
||||
UIImage *image = [UIImage imageWithCGImage:cgImage];
|
||||
return image;
|
||||
}
|
||||
|
||||
- (void)thumbnailImageAtCurrentTime:(void(^)(UIImage *))handler {
|
||||
CMTime expectedTime = self.playerItem.currentTime;
|
||||
[self.imageGenerator generateCGImagesAsynchronouslyForTimes:@[[NSValue valueWithCMTime:expectedTime]] completionHandler:^(CMTime requestedTime, CGImageRef _Nullable image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError * _Nullable error) {
|
||||
if (handler) {
|
||||
UIImage *finalImage = [UIImage imageWithCGImage:image];
|
||||
handler(finalImage);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - private method
|
||||
|
||||
/// Calculate buffer progress
|
||||
- (NSTimeInterval)availableDuration {
|
||||
NSArray *timeRangeArray = _playerItem.loadedTimeRanges;
|
||||
CMTime currentTime = [_player currentTime];
|
||||
BOOL foundRange = NO;
|
||||
CMTimeRange aTimeRange = {0};
|
||||
if (timeRangeArray.count) {
|
||||
aTimeRange = [[timeRangeArray objectAtIndex:0] CMTimeRangeValue];
|
||||
if (CMTimeRangeContainsTime(aTimeRange, currentTime)) {
|
||||
foundRange = YES;
|
||||
}
|
||||
}
|
||||
|
||||
if (foundRange) {
|
||||
CMTime maxTime = CMTimeRangeGetEnd(aTimeRange);
|
||||
NSTimeInterval playableDuration = CMTimeGetSeconds(maxTime);
|
||||
if (playableDuration > 0) {
|
||||
return playableDuration;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)initializePlayer {
|
||||
_asset = [AVURLAsset URLAssetWithURL:self.assetURL options:self.requestHeader];
|
||||
_playerItem = [AVPlayerItem playerItemWithAsset:_asset];
|
||||
_player = [AVPlayer playerWithPlayerItem:_playerItem];
|
||||
_imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:_asset];
|
||||
|
||||
[self enableAudioTracks:YES inPlayerItem:_playerItem];
|
||||
|
||||
ZFPlayerPresentView *presentView = [[ZFPlayerPresentView alloc] init];
|
||||
presentView.player = _player;
|
||||
self.view.playerView = presentView;
|
||||
|
||||
self.scalingMode = _scalingMode;
|
||||
if (@available(iOS 9.0, *)) {
|
||||
_playerItem.canUseNetworkResourcesForLiveStreamingWhilePaused = NO;
|
||||
}
|
||||
if (@available(iOS 10.0, *)) {
|
||||
_playerItem.preferredForwardBufferDuration = 5;
|
||||
/// 关闭AVPlayer默认的缓冲延迟播放策略,提高首屏播放速度
|
||||
_player.automaticallyWaitsToMinimizeStalling = NO;
|
||||
}
|
||||
[self itemObserving];
|
||||
}
|
||||
|
||||
/// Playback speed switching method
|
||||
- (void)enableAudioTracks:(BOOL)enable inPlayerItem:(AVPlayerItem*)playerItem {
|
||||
for (AVPlayerItemTrack *track in playerItem.tracks){
|
||||
if ([track.assetTrack.mediaType isEqual:AVMediaTypeVideo]) {
|
||||
track.enabled = enable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓冲较差时候回调这里
|
||||
*/
|
||||
- (void)bufferingSomeSecond {
|
||||
// playbackBufferEmpty会反复进入,因此在bufferingOneSecond延时播放执行完之前再调用bufferingSomeSecond都忽略
|
||||
if (self.isBuffering || self.playState == ZFPlayerPlayStatePlayStopped) return;
|
||||
/// 没有网络
|
||||
if ([ZFReachabilityManager sharedManager].networkReachabilityStatus == ZFReachabilityStatusNotReachable) return;
|
||||
self.isBuffering = YES;
|
||||
|
||||
// 需要先暂停一小会之后再播放,否则网络状况不好的时候时间在走,声音播放不出来
|
||||
[self pause];
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
// 如果此时用户已经暂停了,则不再需要开启播放了
|
||||
if (!self.isPlaying && self.loadState == ZFPlayerLoadStateStalled) {
|
||||
self.isBuffering = NO;
|
||||
return;
|
||||
}
|
||||
[self play];
|
||||
// 如果执行了play还是没有播放则说明还没有缓存好,则再次缓存一段时间
|
||||
self.isBuffering = NO;
|
||||
if (!self.playerItem.isPlaybackLikelyToKeepUp) [self bufferingSomeSecond];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)itemObserving {
|
||||
[_playerItemKVO safelyRemoveAllObservers];
|
||||
_playerItemKVO = [[ZFKVOController alloc] initWithTarget:_playerItem];
|
||||
[_playerItemKVO safelyAddObserver:self
|
||||
forKeyPath:kStatus
|
||||
options:NSKeyValueObservingOptionNew
|
||||
context:nil];
|
||||
[_playerItemKVO safelyAddObserver:self
|
||||
forKeyPath:kPlaybackBufferEmpty
|
||||
options:NSKeyValueObservingOptionNew
|
||||
context:nil];
|
||||
[_playerItemKVO safelyAddObserver:self
|
||||
forKeyPath:kPlaybackLikelyToKeepUp
|
||||
options:NSKeyValueObservingOptionNew
|
||||
context:nil];
|
||||
[_playerItemKVO safelyAddObserver:self
|
||||
forKeyPath:kLoadedTimeRanges
|
||||
options:NSKeyValueObservingOptionNew
|
||||
context:nil];
|
||||
[_playerItemKVO safelyAddObserver:self
|
||||
forKeyPath:kPresentationSize
|
||||
options:NSKeyValueObservingOptionNew
|
||||
context:nil];
|
||||
|
||||
CMTime interval = CMTimeMakeWithSeconds(self.timeRefreshInterval > 0 ? self.timeRefreshInterval : 0.1, NSEC_PER_SEC);
|
||||
@zf_weakify(self)
|
||||
_timeObserver = [self.player addPeriodicTimeObserverForInterval:interval queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
|
||||
@zf_strongify(self)
|
||||
if (!self) return;
|
||||
NSArray *loadedRanges = self.playerItem.seekableTimeRanges;
|
||||
if (self.isPlaying && self.loadState == ZFPlayerLoadStateStalled) self.player.rate = self.rate;
|
||||
if (loadedRanges.count > 0) {
|
||||
if (self.playerPlayTimeChanged) self.playerPlayTimeChanged(self, self.currentTime, self.totalTime);
|
||||
}
|
||||
}];
|
||||
|
||||
_itemEndObserver = [[NSNotificationCenter defaultCenter] addObserverForName:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
|
||||
@zf_strongify(self)
|
||||
if (!self) return;
|
||||
self.playState = ZFPlayerPlayStatePlayStopped;
|
||||
if (self.playerDidToEnd) self.playerDidToEnd(self);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if ([keyPath isEqualToString:kStatus]) {
|
||||
if (self.player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
|
||||
if (!self.isReadyToPlay) {
|
||||
self.isReadyToPlay = YES;
|
||||
self.loadState = ZFPlayerLoadStatePlaythroughOK;
|
||||
if (self.playerReadyToPlay) self.playerReadyToPlay(self, self.assetURL);
|
||||
}
|
||||
if (self.seekTime) {
|
||||
if (self.shouldAutoPlay) [self pause];
|
||||
@zf_weakify(self)
|
||||
[self seekToTime:self.seekTime completionHandler:^(BOOL finished) {
|
||||
@zf_strongify(self)
|
||||
if (finished) {
|
||||
if (self.shouldAutoPlay) [self play];
|
||||
}
|
||||
}];
|
||||
self.seekTime = 0;
|
||||
} else {
|
||||
if (self.shouldAutoPlay && self.isPlaying) [self play];
|
||||
}
|
||||
self.player.muted = self.muted;
|
||||
NSArray *loadedRanges = self.playerItem.seekableTimeRanges;
|
||||
if (loadedRanges.count > 0) {
|
||||
if (self.playerPlayTimeChanged) self.playerPlayTimeChanged(self, self.currentTime, self.totalTime);
|
||||
}
|
||||
} else if (self.player.currentItem.status == AVPlayerItemStatusFailed) {
|
||||
self.playState = ZFPlayerPlayStatePlayFailed;
|
||||
self->_isPlaying = NO;
|
||||
NSError *error = self.player.currentItem.error;
|
||||
if (self.playerPlayFailed) self.playerPlayFailed(self, error);
|
||||
}
|
||||
} else if ([keyPath isEqualToString:kPlaybackBufferEmpty]) {
|
||||
// When the buffer is empty
|
||||
if (self.playerItem.playbackBufferEmpty) {
|
||||
self.loadState = ZFPlayerLoadStateStalled;
|
||||
[self bufferingSomeSecond];
|
||||
}
|
||||
} else if ([keyPath isEqualToString:kPlaybackLikelyToKeepUp]) {
|
||||
// When the buffer is good
|
||||
if (self.playerItem.playbackLikelyToKeepUp) {
|
||||
self.loadState = ZFPlayerLoadStatePlayable;
|
||||
if (self.isPlaying) [self.player play];
|
||||
}
|
||||
} else if ([keyPath isEqualToString:kLoadedTimeRanges]) {
|
||||
NSTimeInterval bufferTime = [self availableDuration];
|
||||
self->_bufferTime = bufferTime;
|
||||
if (self.playerBufferTimeChanged) self.playerBufferTimeChanged(self, bufferTime);
|
||||
} else if ([keyPath isEqualToString:kPresentationSize]) {
|
||||
self.presentationSize = self.playerItem.presentationSize;
|
||||
} else {
|
||||
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (ZFPlayerView *)view {
|
||||
if (!_view) {
|
||||
ZFPlayerView *view = [[ZFPlayerView alloc] init];
|
||||
_view = view;
|
||||
}
|
||||
return _view;
|
||||
}
|
||||
|
||||
- (AVPlayerLayer *)avPlayerLayer {
|
||||
ZFPlayerPresentView *view = (ZFPlayerPresentView *)self.view.playerView;
|
||||
return [view avLayer];
|
||||
}
|
||||
|
||||
- (float)rate {
|
||||
return _rate == 0 ?1:_rate;
|
||||
}
|
||||
|
||||
- (NSTimeInterval)totalTime {
|
||||
NSTimeInterval sec = CMTimeGetSeconds(self.player.currentItem.duration);
|
||||
if (isnan(sec)) {
|
||||
return 0;
|
||||
}
|
||||
return sec;
|
||||
}
|
||||
|
||||
- (NSTimeInterval)currentTime {
|
||||
NSTimeInterval sec = CMTimeGetSeconds(self.playerItem.currentTime);
|
||||
if (isnan(sec) || sec < 0) {
|
||||
return 0;
|
||||
}
|
||||
return sec;
|
||||
}
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (void)setPlayState:(ZFPlayerPlaybackState)playState {
|
||||
_playState = playState;
|
||||
if (self.playerPlayStateChanged) self.playerPlayStateChanged(self, playState);
|
||||
}
|
||||
|
||||
- (void)setLoadState:(ZFPlayerLoadState)loadState {
|
||||
_loadState = loadState;
|
||||
if (self.playerLoadStateChanged) self.playerLoadStateChanged(self, loadState);
|
||||
}
|
||||
|
||||
- (void)setAssetURL:(NSURL *)assetURL {
|
||||
if (self.player) [self stop];
|
||||
_assetURL = assetURL;
|
||||
[self prepareToPlay];
|
||||
}
|
||||
|
||||
- (void)setRate:(float)rate {
|
||||
_rate = rate;
|
||||
if (self.player && fabsf(_player.rate) > 0.00001f) {
|
||||
self.player.rate = rate;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setMuted:(BOOL)muted {
|
||||
_muted = muted;
|
||||
self.player.muted = muted;
|
||||
}
|
||||
|
||||
- (void)setScalingMode:(ZFPlayerScalingMode)scalingMode {
|
||||
_scalingMode = scalingMode;
|
||||
ZFPlayerPresentView *presentView = (ZFPlayerPresentView *)self.view.playerView;
|
||||
self.view.scalingMode = scalingMode;
|
||||
switch (scalingMode) {
|
||||
case ZFPlayerScalingModeNone:
|
||||
presentView.videoGravity = AVLayerVideoGravityResizeAspect;
|
||||
break;
|
||||
case ZFPlayerScalingModeAspectFit:
|
||||
presentView.videoGravity = AVLayerVideoGravityResizeAspect;
|
||||
break;
|
||||
case ZFPlayerScalingModeAspectFill:
|
||||
presentView.videoGravity = AVLayerVideoGravityResizeAspectFill;
|
||||
break;
|
||||
case ZFPlayerScalingModeFill:
|
||||
presentView.videoGravity = AVLayerVideoGravityResize;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setVolume:(float)volume {
|
||||
_volume = MIN(MAX(0, volume), 1);
|
||||
self.player.volume = _volume;
|
||||
}
|
||||
|
||||
- (void)setPresentationSize:(CGSize)presentationSize {
|
||||
_presentationSize = presentationSize;
|
||||
self.view.presentationSize = presentationSize;
|
||||
if (self.presentationSizeChanged) {
|
||||
self.presentationSizeChanged(self, self.presentationSize);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
127
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIImageView+ZFCache.h
generated
Normal file
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// UIImageView+ZFCache.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
typedef void (^ZFDownLoadDataCallBack)(NSData *data, NSError *error);
|
||||
typedef void (^ZFDownloadProgressBlock)(unsigned long long total, unsigned long long current);
|
||||
|
||||
@interface ZFImageDownloader : NSObject<NSURLSessionDownloadDelegate>
|
||||
|
||||
@property (nonatomic, strong) NSURLSession *session;
|
||||
@property (nonatomic, strong) NSURLSessionDownloadTask *task;
|
||||
|
||||
@property (nonatomic, assign) unsigned long long totalLength;
|
||||
@property (nonatomic, assign) unsigned long long currentLength;
|
||||
|
||||
@property (nonatomic, copy) ZFDownloadProgressBlock progressBlock;
|
||||
@property (nonatomic, copy) ZFDownLoadDataCallBack callbackOnFinished;
|
||||
|
||||
- (void)startDownloadImageWithUrl:(NSString *)url
|
||||
progress:(ZFDownloadProgressBlock)progress
|
||||
finished:(ZFDownLoadDataCallBack)finished;
|
||||
|
||||
@end
|
||||
|
||||
typedef void (^ZFImageBlock)(UIImage *image);
|
||||
|
||||
@interface UIImageView (ZFCache)
|
||||
|
||||
/**
|
||||
* Get/Set the callback block when download the image finished.
|
||||
*
|
||||
* The image object from network or from disk.
|
||||
*/
|
||||
@property (nonatomic, copy) ZFImageBlock completion;
|
||||
|
||||
/**
|
||||
* Image downloader
|
||||
*/
|
||||
@property (nonatomic, strong) ZFImageDownloader *imageDownloader;
|
||||
|
||||
/**
|
||||
* Specify the URL to download images fails, the number of retries, the default is 2
|
||||
*/
|
||||
@property (nonatomic, assign) NSUInteger attemptToReloadTimesForFailedURL;
|
||||
|
||||
/**
|
||||
* Will automatically download to cutting for UIImageView size of image.The default value is NO.
|
||||
* If set to YES, then the download after a successful store only after cutting the image
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL shouldAutoClipImageToViewSize;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url` and a placeholder.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholderImageName The image name to be set initially, until the image request finishes.
|
||||
*/
|
||||
- (void)setImageWithURLString:(NSString *)url placeholderImageName:(NSString *)placeholderImageName;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url` and a placeholder.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholderImage The image to be set initially, until the image request finishes.
|
||||
*/
|
||||
- (void)setImageWithURLString:(NSString *)url placeholder:(UIImage *)placeholderImage;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholderImage The image to be set initially, until the image request finishes.
|
||||
* @param completion A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)setImageWithURLString:(NSString *)url
|
||||
placeholder:(UIImage *)placeholderImage
|
||||
completion:(void (^)(UIImage *image))completion;
|
||||
|
||||
/**
|
||||
* Set the imageView `image` with an `url`, placeholder.
|
||||
*
|
||||
* The download is asynchronous and cached.
|
||||
*
|
||||
* @param url The url for the image.
|
||||
* @param placeholderImageName The image name to be set initially, until the image request finishes.
|
||||
* @param completion A block called when operation has been completed. This block has no return value
|
||||
* and takes the requested UIImage as first parameter. In case of error the image parameter
|
||||
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
|
||||
* indicating if the image was retrieved from the local cache or from the network.
|
||||
* The fourth parameter is the original image url.
|
||||
*/
|
||||
- (void)setImageWithURLString:(NSString *)url
|
||||
placeholderImageName:(NSString *)placeholderImageName
|
||||
completion:(void (^)(UIImage *image))completion;
|
||||
@end
|
||||
411
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIImageView+ZFCache.m
generated
Normal file
@@ -0,0 +1,411 @@
|
||||
//
|
||||
// UIImageView+ZFCache.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "UIImageView+ZFCache.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
@implementation ZFImageDownloader
|
||||
|
||||
- (void)startDownloadImageWithUrl:(NSString *)url
|
||||
progress:(ZFDownloadProgressBlock)progress
|
||||
finished:(ZFDownLoadDataCallBack)finished {
|
||||
self.progressBlock = progress;
|
||||
self.callbackOnFinished = finished;
|
||||
|
||||
if ([NSURL URLWithString:url] == nil) {
|
||||
if (finished) { finished(nil, nil); }
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
|
||||
cachePolicy:NSURLRequestReturnCacheDataElseLoad
|
||||
timeoutInterval:60];
|
||||
[request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
|
||||
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
|
||||
self.session = [NSURLSession sessionWithConfiguration:config
|
||||
delegate:self
|
||||
delegateQueue:queue];
|
||||
NSURLSessionDownloadTask *task = [self.session downloadTaskWithRequest:request];
|
||||
[task resume];
|
||||
self.task = task;
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
|
||||
NSData *data = [NSData dataWithContentsOfURL:location];
|
||||
|
||||
if (self.progressBlock) {
|
||||
self.progressBlock(self.totalLength, self.currentLength);
|
||||
}
|
||||
|
||||
if (self.callbackOnFinished) {
|
||||
self.callbackOnFinished(data, nil);
|
||||
|
||||
// 防止重复调用
|
||||
self.callbackOnFinished = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite {
|
||||
self.currentLength = totalBytesWritten;
|
||||
self.totalLength = totalBytesExpectedToWrite;
|
||||
|
||||
if (self.progressBlock) {
|
||||
self.progressBlock(self.totalLength, self.currentLength);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
|
||||
if ([error code] != NSURLErrorCancelled) {
|
||||
if (self.callbackOnFinished) {
|
||||
self.callbackOnFinished(nil, error);
|
||||
}
|
||||
self.callbackOnFinished = nil;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface NSString (md5)
|
||||
|
||||
+ (NSString *)cachedFileNameForKey:(NSString *)key;
|
||||
+ (NSString *)zf_cachePath;
|
||||
+ (NSString *)zf_keyForRequest:(NSURLRequest *)request;
|
||||
|
||||
@end
|
||||
|
||||
@implementation NSString (md5)
|
||||
|
||||
+ (NSString *)zf_keyForRequest:(NSURLRequest *)request {
|
||||
return request.URL.absoluteString;
|
||||
}
|
||||
|
||||
+ (NSString *)zf_cachePath {
|
||||
NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
|
||||
NSString *directoryPath = [NSString stringWithFormat:@"%@/%@/%@",cachePath,@"default",@"com.hackemist.SDWebImageCache.default"];
|
||||
return directoryPath;
|
||||
}
|
||||
|
||||
+ (NSString *)cachedFileNameForKey:(NSString *)key {
|
||||
const char *str = [key UTF8String];
|
||||
if (str == NULL) {
|
||||
str = "";
|
||||
}
|
||||
unsigned char r[CC_MD5_DIGEST_LENGTH];
|
||||
CC_MD5(str, (CC_LONG)strlen(str), r);
|
||||
NSString *filename = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%@",
|
||||
r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], r[10],
|
||||
r[11], r[12], r[13], r[14], r[15], [[key pathExtension] isEqualToString:@""] ? @"" : [NSString stringWithFormat:@".%@", [key pathExtension]]];
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface UIApplication (ZFCacheImage)
|
||||
|
||||
@property (nonatomic, strong, readonly) NSMutableDictionary *zf_cacheFaileTimes;
|
||||
|
||||
- (UIImage *)zf_cacheImageForRequest:(NSURLRequest *)request;
|
||||
- (void)zf_cacheImage:(UIImage *)image forRequest:(NSURLRequest *)request;
|
||||
- (void)zf_cacheFailRequest:(NSURLRequest *)request;
|
||||
- (NSUInteger)zf_failTimesForRequest:(NSURLRequest *)request;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIApplication (ZFCacheImage)
|
||||
|
||||
- (NSMutableDictionary *)zf_cacheFaileTimes {
|
||||
NSMutableDictionary *dict = objc_getAssociatedObject(self, _cmd);
|
||||
if (!dict) {
|
||||
dict = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
|
||||
- (void)setZf_cacheFaileTimes:(NSMutableDictionary *)zf_cacheFaileTimes {
|
||||
objc_setAssociatedObject(self, @selector(zf_cacheFaileTimes), zf_cacheFaileTimes, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)zf_clearCache {
|
||||
[self.zf_cacheFaileTimes removeAllObjects];
|
||||
self.zf_cacheFaileTimes = nil;
|
||||
}
|
||||
|
||||
- (void)zf_clearDiskCaches {
|
||||
NSString *directoryPath = [NSString zf_cachePath];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) {
|
||||
dispatch_queue_t ioQueue = dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
|
||||
dispatch_async(ioQueue, ^{
|
||||
[[NSFileManager defaultManager] removeItemAtPath:directoryPath error:nil];
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:directoryPath
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:nil];
|
||||
});
|
||||
}
|
||||
[self zf_clearCache];
|
||||
}
|
||||
|
||||
- (UIImage *)zf_cacheImageForRequest:(NSURLRequest *)request {
|
||||
if (request) {
|
||||
NSString *directoryPath = [NSString zf_cachePath];
|
||||
NSString *path = [NSString stringWithFormat:@"%@/%@", directoryPath, [NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
|
||||
return [UIImage imageWithContentsOfFile:path];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSUInteger)zf_failTimesForRequest:(NSURLRequest *)request {
|
||||
NSNumber *faileTimes = [self.zf_cacheFaileTimes objectForKey:[NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
|
||||
if (faileTimes && [faileTimes respondsToSelector:@selector(integerValue)]) {
|
||||
return faileTimes.integerValue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (void)zf_cacheFailRequest:(NSURLRequest *)request {
|
||||
NSNumber *faileTimes = [self.zf_cacheFaileTimes objectForKey:[NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
|
||||
NSUInteger times = 0;
|
||||
if (faileTimes && [faileTimes respondsToSelector:@selector(integerValue)]) {
|
||||
times = [faileTimes integerValue];
|
||||
}
|
||||
|
||||
times++;
|
||||
|
||||
[self.zf_cacheFaileTimes setObject:@(times) forKey:[NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
|
||||
}
|
||||
|
||||
- (void)zf_cacheImage:(UIImage *)image forRequest:(NSURLRequest *)request {
|
||||
if (!image || !request) { return; }
|
||||
|
||||
NSString *directoryPath = [NSString zf_cachePath];
|
||||
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) {
|
||||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:directoryPath
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:&error];
|
||||
if (error) { return; }
|
||||
}
|
||||
|
||||
NSString *path = [NSString stringWithFormat:@"%@/%@", directoryPath, [NSString cachedFileNameForKey:[NSString zf_keyForRequest:request]]];
|
||||
NSData *data = UIImagePNGRepresentation(image);
|
||||
if (data) {
|
||||
[[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation UIImageView (ZFCache)
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (ZFImageBlock)completion {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (ZFImageDownloader *)imageDownloader {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (NSUInteger)attemptToReloadTimesForFailedURL {
|
||||
NSUInteger count = [objc_getAssociatedObject(self, _cmd) integerValue];
|
||||
if (count == 0) { count = 2; }
|
||||
return count;
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutoClipImageToViewSize {
|
||||
return [objc_getAssociatedObject(self, _cmd) boolValue];
|
||||
}
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (void)setCompletion:(ZFImageBlock)completion {
|
||||
objc_setAssociatedObject(self, @selector(completion), completion, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setImageDownloader:(ZFImageDownloader *)imageDownloader {
|
||||
objc_setAssociatedObject(self, @selector(imageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setAttemptToReloadTimesForFailedURL:(NSUInteger)attemptToReloadTimesForFailedURL {
|
||||
objc_setAssociatedObject(self, @selector(attemptToReloadTimesForFailedURL), @(attemptToReloadTimesForFailedURL), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setShouldAutoClipImageToViewSize:(BOOL)shouldAutoClipImageToViewSize {
|
||||
objc_setAssociatedObject(self, @selector(shouldAutoClipImageToViewSize), @(shouldAutoClipImageToViewSize), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
#pragma mark - public method
|
||||
|
||||
- (void)setImageWithURLString:(NSString *)url
|
||||
placeholderImageName:(NSString *)placeholderImageName {
|
||||
return [self setImageWithURLString:url placeholderImageName:placeholderImageName completion:nil];
|
||||
}
|
||||
|
||||
- (void)setImageWithURLString:(NSString *)url placeholder:(UIImage *)placeholderImage {
|
||||
return [self setImageWithURLString:url placeholder:placeholderImage completion:nil];
|
||||
}
|
||||
|
||||
- (void)setImageWithURLString:(NSString *)url
|
||||
placeholderImageName:(NSString *)placeholderImage
|
||||
completion:(void (^)(UIImage *image))completion {
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:placeholderImage ofType:nil];
|
||||
UIImage *image = [UIImage imageWithContentsOfFile:path];
|
||||
if (image == nil) { image = [UIImage imageNamed:placeholderImage]; }
|
||||
|
||||
[self setImageWithURLString:url placeholder:image completion:completion];
|
||||
}
|
||||
|
||||
- (void)setImageWithURLString:(NSString *)url
|
||||
placeholder:(UIImage *)placeholderImageName
|
||||
completion:(void (^)(UIImage *image))completion {
|
||||
[self.layer removeAllAnimations];
|
||||
self.completion = completion;
|
||||
|
||||
if (url == nil || [url isKindOfClass:[NSNull class]] || (![url hasPrefix:@"http://"] && ![url hasPrefix:@"https://"])) {
|
||||
[self setImage:placeholderImageName isFromCache:YES];
|
||||
|
||||
if (completion) {
|
||||
self.completion(self.image);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
|
||||
[self downloadWithReqeust:request holder:placeholderImageName];
|
||||
}
|
||||
|
||||
#pragma mark - private method
|
||||
|
||||
- (void)downloadWithReqeust:(NSURLRequest *)theRequest holder:(UIImage *)holder {
|
||||
UIImage *cachedImage = [[UIApplication sharedApplication] zf_cacheImageForRequest:theRequest];
|
||||
|
||||
if (cachedImage) {
|
||||
[self setImage:cachedImage isFromCache:YES];
|
||||
if (self.completion) {
|
||||
self.completion(cachedImage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
[self setImage:holder isFromCache:YES];
|
||||
|
||||
if ([[UIApplication sharedApplication] zf_failTimesForRequest:theRequest] >= self.attemptToReloadTimesForFailedURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self cancelRequest];
|
||||
self.imageDownloader = nil;
|
||||
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
|
||||
self.imageDownloader = [[ZFImageDownloader alloc] init];
|
||||
[self.imageDownloader startDownloadImageWithUrl:theRequest.URL.absoluteString progress:nil finished:^(NSData *data, NSError *error) {
|
||||
// success
|
||||
if (data != nil && error == nil) {
|
||||
dispatch_async(dispatch_get_global_queue(0, 0), ^{
|
||||
UIImage *image = [UIImage imageWithData:data];
|
||||
UIImage *finalImage = image;
|
||||
|
||||
if (image) {
|
||||
if (weakSelf.shouldAutoClipImageToViewSize) {
|
||||
// cutting
|
||||
if (fabs(weakSelf.frame.size.width - image.size.width) != 0
|
||||
&& fabs(weakSelf.frame.size.height - image.size.height) != 0) {
|
||||
finalImage = [self clipImage:image toSize:weakSelf.frame.size isScaleToMax:YES];
|
||||
}
|
||||
}
|
||||
|
||||
[[UIApplication sharedApplication] zf_cacheImage:finalImage forRequest:theRequest];
|
||||
} else {
|
||||
[[UIApplication sharedApplication] zf_cacheFailRequest:theRequest];
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (finalImage) {
|
||||
[weakSelf setImage:finalImage isFromCache:NO];
|
||||
|
||||
if (weakSelf.completion) {
|
||||
weakSelf.completion(weakSelf.image);
|
||||
}
|
||||
} else {// error data
|
||||
if (weakSelf.completion) {
|
||||
weakSelf.completion(weakSelf.image);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
} else { // error
|
||||
[[UIApplication sharedApplication] zf_cacheFailRequest:theRequest];
|
||||
|
||||
if (weakSelf.completion) {
|
||||
weakSelf.completion(weakSelf.image);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setImage:(UIImage *)image isFromCache:(BOOL)isFromCache {
|
||||
self.image = image;
|
||||
if (!isFromCache) {
|
||||
CATransition *animation = [CATransition animation];
|
||||
[animation setDuration:0.6f];
|
||||
[animation setType:kCATransitionFade];
|
||||
animation.removedOnCompletion = YES;
|
||||
[self.layer addAnimation:animation forKey:@"transition"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelRequest {
|
||||
[self.imageDownloader.task cancel];
|
||||
}
|
||||
|
||||
- (UIImage *)clipImage:(UIImage *)image toSize:(CGSize)size isScaleToMax:(BOOL)isScaleToMax {
|
||||
CGFloat scale = [UIScreen mainScreen].scale;
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(size, NO, scale);
|
||||
|
||||
CGSize aspectFitSize = CGSizeZero;
|
||||
if (image.size.width != 0 && image.size.height != 0) {
|
||||
CGFloat rateWidth = size.width / image.size.width;
|
||||
CGFloat rateHeight = size.height / image.size.height;
|
||||
|
||||
CGFloat rate = isScaleToMax ? MAX(rateHeight, rateWidth) : MIN(rateHeight, rateWidth);
|
||||
aspectFitSize = CGSizeMake(image.size.width * rate, image.size.height * rate);
|
||||
}
|
||||
|
||||
[image drawInRect:CGRectMake(0, 0, aspectFitSize.width, aspectFitSize.height)];
|
||||
UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
|
||||
return finalImage;
|
||||
}
|
||||
|
||||
@end
|
||||
45
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIView+ZFFrame.h
generated
Normal file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// UIView+ZFFrame.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIView (ZFFrame)
|
||||
|
||||
@property (nonatomic) CGFloat zf_x;
|
||||
@property (nonatomic) CGFloat zf_y;
|
||||
@property (nonatomic) CGFloat zf_width;
|
||||
@property (nonatomic) CGFloat zf_height;
|
||||
|
||||
@property (nonatomic) CGFloat zf_top;
|
||||
@property (nonatomic) CGFloat zf_bottom;
|
||||
@property (nonatomic) CGFloat zf_left;
|
||||
@property (nonatomic) CGFloat zf_right;
|
||||
|
||||
@property (nonatomic) CGFloat zf_centerX;
|
||||
@property (nonatomic) CGFloat zf_centerY;
|
||||
|
||||
@property (nonatomic) CGPoint zf_origin;
|
||||
@property (nonatomic) CGSize zf_size;
|
||||
|
||||
@end
|
||||
149
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/UIView+ZFFrame.m
generated
Normal file
@@ -0,0 +1,149 @@
|
||||
//
|
||||
// UIView+ZFFrame.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "UIView+ZFFrame.h"
|
||||
|
||||
@implementation UIView (ZFFrame)
|
||||
|
||||
- (CGFloat)zf_x {
|
||||
return self.frame.origin.x;
|
||||
}
|
||||
|
||||
- (void)setZf_x:(CGFloat)zf_x {
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.origin.x = zf_x;
|
||||
self.frame = newFrame;
|
||||
}
|
||||
|
||||
- (CGFloat)zf_y {
|
||||
return self.frame.origin.y;
|
||||
}
|
||||
|
||||
- (void)setZf_y:(CGFloat)zf_y {
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.origin.y = zf_y;
|
||||
self.frame = newFrame;
|
||||
}
|
||||
|
||||
- (CGFloat)zf_width {
|
||||
return CGRectGetWidth(self.bounds);
|
||||
}
|
||||
|
||||
- (void)setZf_width:(CGFloat)zf_width {
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.size.width = zf_width;
|
||||
self.frame = newFrame;
|
||||
}
|
||||
|
||||
- (CGFloat)zf_height {
|
||||
return CGRectGetHeight(self.bounds);
|
||||
}
|
||||
|
||||
- (void)setZf_height:(CGFloat)zf_height {
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.size.height = zf_height;
|
||||
self.frame = newFrame;
|
||||
}
|
||||
|
||||
- (CGFloat)zf_top {
|
||||
return self.frame.origin.y;
|
||||
}
|
||||
|
||||
- (void)setZf_top:(CGFloat)zf_top {
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.origin.y = zf_top;
|
||||
self.frame = newFrame;
|
||||
}
|
||||
|
||||
- (CGFloat)zf_bottom {
|
||||
return self.frame.origin.y + self.frame.size.height;
|
||||
}
|
||||
|
||||
- (void)setZf_bottom:(CGFloat)zf_bottom {
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.origin.y = zf_bottom - self.frame.size.height;
|
||||
self.frame = newFrame;
|
||||
}
|
||||
|
||||
- (CGFloat)zf_left {
|
||||
return self.frame.origin.x;
|
||||
}
|
||||
|
||||
- (void)setZf_left:(CGFloat)zf_left {
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.origin.x = zf_left;
|
||||
self.frame = newFrame;
|
||||
}
|
||||
|
||||
- (CGFloat)zf_right {
|
||||
return self.frame.origin.x + self.frame.size.width;
|
||||
}
|
||||
|
||||
- (void)setZf_right:(CGFloat)zf_right {
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.origin.x = zf_right - self.frame.size.width;
|
||||
self.frame = newFrame;
|
||||
}
|
||||
|
||||
- (CGFloat)zf_centerX {
|
||||
return self.center.x;
|
||||
}
|
||||
|
||||
- (void)setZf_centerX:(CGFloat)zf_centerX {
|
||||
CGPoint newCenter = self.center;
|
||||
newCenter.x = zf_centerX;
|
||||
self.center = newCenter;
|
||||
}
|
||||
|
||||
- (CGFloat)zf_centerY {
|
||||
return self.center.y;
|
||||
}
|
||||
|
||||
- (void)setZf_centerY:(CGFloat)zf_centerY {
|
||||
CGPoint newCenter = self.center;
|
||||
newCenter.y = zf_centerY;
|
||||
self.center = newCenter;
|
||||
}
|
||||
|
||||
- (CGPoint)zf_origin {
|
||||
return self.frame.origin;
|
||||
}
|
||||
|
||||
- (void)setZf_origin:(CGPoint)zf_origin {
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.origin = zf_origin;
|
||||
self.frame = newFrame;
|
||||
}
|
||||
|
||||
- (CGSize)zf_size {
|
||||
return self.frame.size;
|
||||
}
|
||||
|
||||
- (void)setZf_size:(CGSize)zf_size {
|
||||
CGRect newFrame = self.frame;
|
||||
newFrame.size = zf_size;
|
||||
self.frame = newFrame;
|
||||
}
|
||||
|
||||
@end
|
||||
126
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLandScapeControlView.h
generated
Executable file
@@ -0,0 +1,126 @@
|
||||
//
|
||||
// ZFLandScapeControlView.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ZFSliderView.h"
|
||||
#if __has_include(<ZFPlayer/ZFPlayerController.h>)
|
||||
#import <ZFPlayer/ZFPlayerController.h>
|
||||
#else
|
||||
#import "ZFPlayerController.h"
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ZFLandScapeControlView : UIView
|
||||
|
||||
/// 顶部工具栏
|
||||
@property (nonatomic, strong, readonly) UIView *topToolView;
|
||||
|
||||
/// 返回按钮
|
||||
@property (nonatomic, strong, readonly) UIButton *backBtn;
|
||||
|
||||
/// 标题
|
||||
@property (nonatomic, strong, readonly) UILabel *titleLabel;
|
||||
|
||||
/// 底部工具栏
|
||||
@property (nonatomic, strong, readonly) UIView *bottomToolView;
|
||||
|
||||
/// 播放或暂停按钮
|
||||
@property (nonatomic, strong, readonly) UIButton *playOrPauseBtn;
|
||||
|
||||
/// 播放的当前时间
|
||||
@property (nonatomic, strong, readonly) UILabel *currentTimeLabel;
|
||||
|
||||
/// 滑杆
|
||||
@property (nonatomic, strong, readonly) ZFSliderView *slider;
|
||||
|
||||
/// 视频总时间
|
||||
@property (nonatomic, strong, readonly) UILabel *totalTimeLabel;
|
||||
|
||||
/// 锁定屏幕按钮
|
||||
@property (nonatomic, strong, readonly) UIButton *lockBtn;
|
||||
|
||||
/// 横屏时候是否显示自定义状态栏(iOS13+),默认 NO.
|
||||
@property (nonatomic, assign) BOOL showCustomStatusBar;
|
||||
|
||||
/// 播放器
|
||||
@property (nonatomic, weak) ZFPlayerController *player;
|
||||
|
||||
/// slider滑动中
|
||||
@property (nonatomic, copy, nullable) void(^sliderValueChanging)(CGFloat value,BOOL forward);
|
||||
|
||||
/// slider滑动结束
|
||||
@property (nonatomic, copy, nullable) void(^sliderValueChanged)(CGFloat value);
|
||||
|
||||
/// 返回按钮点击回调
|
||||
@property (nonatomic, copy) void(^backBtnClickCallback)(void);
|
||||
|
||||
/// 如果是暂停状态,seek完是否播放,默认YES
|
||||
@property (nonatomic, assign) BOOL seekToPlay;
|
||||
|
||||
/// 全屏模式
|
||||
@property (nonatomic, assign) ZFFullScreenMode fullScreenMode;
|
||||
|
||||
/// 重置控制层
|
||||
- (void)resetControlView;
|
||||
|
||||
/// 显示控制层
|
||||
- (void)showControlView;
|
||||
|
||||
/// 隐藏控制层
|
||||
- (void)hideControlView;
|
||||
|
||||
/// 设置播放时间
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime;
|
||||
|
||||
/// 设置缓冲时间
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime;
|
||||
|
||||
/// 是否响应该手势
|
||||
- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch;
|
||||
|
||||
/// 视频尺寸改变
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer presentationSizeChanged:(CGSize)size;
|
||||
|
||||
/// 视频view已经旋转
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer orientationWillChange:(ZFOrientationObserver *)observer;
|
||||
|
||||
/// 标题和全屏模式
|
||||
- (void)showTitle:(NSString *_Nullable)title fullScreenMode:(ZFFullScreenMode)fullScreenMode;
|
||||
|
||||
/// 根据当前播放状态取反
|
||||
- (void)playOrPause;
|
||||
|
||||
/// 播放按钮状态
|
||||
- (void)playBtnSelectedState:(BOOL)selected;
|
||||
|
||||
/// 调节播放进度slider和当前时间更新
|
||||
- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString;
|
||||
|
||||
/// 滑杆结束滑动
|
||||
- (void)sliderChangeEnded;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
501
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLandScapeControlView.m
generated
Executable file
@@ -0,0 +1,501 @@
|
||||
//
|
||||
// ZFLandScapeControlView.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLandScapeControlView.h"
|
||||
#import "UIView+ZFFrame.h"
|
||||
#import "ZFUtilities.h"
|
||||
#import "ZFPlayerStatusBar.h"
|
||||
#if __has_include(<ZFPlayer/ZFPlayer.h>)
|
||||
#import <ZFPlayer/ZFPlayerConst.h>
|
||||
#else
|
||||
#import "ZFPlayerConst.h"
|
||||
#endif
|
||||
|
||||
@interface ZFLandScapeControlView () <ZFSliderViewDelegate>
|
||||
|
||||
@property (nonatomic, strong) ZFPlayerStatusBar *statusBarView;
|
||||
/// 顶部工具栏
|
||||
@property (nonatomic, strong) UIView *topToolView;
|
||||
/// 返回按钮
|
||||
@property (nonatomic, strong) UIButton *backBtn;
|
||||
/// 标题
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
/// 底部工具栏
|
||||
@property (nonatomic, strong) UIView *bottomToolView;
|
||||
/// 播放或暂停按钮
|
||||
@property (nonatomic, strong) UIButton *playOrPauseBtn;
|
||||
/// 播放的当前时间
|
||||
@property (nonatomic, strong) UILabel *currentTimeLabel;
|
||||
/// 滑杆
|
||||
@property (nonatomic, strong) ZFSliderView *slider;
|
||||
/// 视频总时间
|
||||
@property (nonatomic, strong) UILabel *totalTimeLabel;
|
||||
/// 锁定屏幕按钮
|
||||
@property (nonatomic, strong) UIButton *lockBtn;
|
||||
|
||||
@property (nonatomic, assign) BOOL isShow;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFLandScapeControlView
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self addSubview:self.topToolView];
|
||||
[self.topToolView addSubview:self.statusBarView];
|
||||
[self.topToolView addSubview:self.backBtn];
|
||||
[self.topToolView addSubview:self.titleLabel];
|
||||
[self addSubview:self.bottomToolView];
|
||||
[self.bottomToolView addSubview:self.playOrPauseBtn];
|
||||
[self.bottomToolView addSubview:self.currentTimeLabel];
|
||||
|
||||
[self.bottomToolView addSubview:self.slider];
|
||||
[self.bottomToolView addSubview:self.totalTimeLabel];
|
||||
[self addSubview:self.lockBtn];
|
||||
|
||||
// 设置子控件的响应事件
|
||||
[self makeSubViewsAction];
|
||||
[self resetControlView];
|
||||
|
||||
/// statusBarFrame changed
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(layoutControllerViews) name:UIApplicationDidChangeStatusBarFrameNotification object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
CGFloat min_x = 0;
|
||||
CGFloat min_y = 0;
|
||||
CGFloat min_w = 0;
|
||||
CGFloat min_h = 0;
|
||||
CGFloat min_view_w = self.bounds.size.width;
|
||||
CGFloat min_view_h = self.bounds.size.height;
|
||||
|
||||
CGFloat min_margin = 9;
|
||||
|
||||
min_x = 0;
|
||||
min_y = 0;
|
||||
min_w = min_view_w;
|
||||
min_h = iPhoneX ? 110 : 80;
|
||||
self.topToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = 0;
|
||||
min_y = 0;
|
||||
min_w = min_view_w;
|
||||
min_h = 20;
|
||||
self.statusBarView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: 15;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if (self.showCustomStatusBar) {
|
||||
min_y = self.statusBarView.zf_bottom;
|
||||
} else {
|
||||
min_y = UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation) ? 10 : (iPhoneX ? 40 : 20);
|
||||
}
|
||||
} else {
|
||||
min_y = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 10: (iPhoneX ? 40 : 20);
|
||||
}
|
||||
min_w = 40;
|
||||
min_h = 40;
|
||||
self.backBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = self.backBtn.zf_right + 5;
|
||||
min_y = 0;
|
||||
min_w = min_view_w - min_x - 15 ;
|
||||
min_h = 30;
|
||||
self.titleLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.titleLabel.zf_centerY = self.backBtn.zf_centerY;
|
||||
|
||||
min_h = iPhoneX ? 100 : 73;
|
||||
min_x = 0;
|
||||
min_y = min_view_h - min_h;
|
||||
min_w = min_view_w;
|
||||
self.bottomToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: 15;
|
||||
min_y = 32;
|
||||
min_w = 30;
|
||||
min_h = 30;
|
||||
self.playOrPauseBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = self.playOrPauseBtn.zf_right + 4;
|
||||
min_y = 0;
|
||||
min_w = 62;
|
||||
min_h = 30;
|
||||
self.currentTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.currentTimeLabel.zf_centerY = self.playOrPauseBtn.zf_centerY;
|
||||
|
||||
min_w = 62;
|
||||
min_x = self.bottomToolView.zf_width - min_w - ((iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 44: min_margin);
|
||||
min_y = 0;
|
||||
min_h = 30;
|
||||
self.totalTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.totalTimeLabel.zf_centerY = self.playOrPauseBtn.zf_centerY;
|
||||
|
||||
min_x = self.currentTimeLabel.zf_right + 4;
|
||||
min_y = 0;
|
||||
min_w = self.totalTimeLabel.zf_left - min_x - 4;
|
||||
min_h = 30;
|
||||
self.slider.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.slider.zf_centerY = self.playOrPauseBtn.zf_centerY;
|
||||
|
||||
min_x = (iPhoneX && UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) ? 50: 18;
|
||||
min_y = 0;
|
||||
min_w = 40;
|
||||
min_h = 40;
|
||||
self.lockBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.lockBtn.zf_centerY = self.zf_centerY;
|
||||
|
||||
if (!self.isShow) {
|
||||
self.topToolView.zf_y = -self.topToolView.zf_height;
|
||||
self.bottomToolView.zf_y = self.zf_height;
|
||||
self.lockBtn.zf_left = iPhoneX ? -82: -47;
|
||||
} else {
|
||||
self.lockBtn.zf_left = iPhoneX ? 50: 18;
|
||||
if (self.player.isLockedScreen) {
|
||||
self.topToolView.zf_y = -self.topToolView.zf_height;
|
||||
self.bottomToolView.zf_y = self.zf_height;
|
||||
} else {
|
||||
self.topToolView.zf_y = 0;
|
||||
self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)makeSubViewsAction {
|
||||
[self.backBtn addTarget:self action:@selector(backBtnClickAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self.playOrPauseBtn addTarget:self action:@selector(playPauseButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self.lockBtn addTarget:self action:@selector(lockButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
|
||||
#pragma mark - action
|
||||
|
||||
- (void)layoutControllerViews {
|
||||
[self layoutIfNeeded];
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)backBtnClickAction:(UIButton *)sender {
|
||||
self.lockBtn.selected = NO;
|
||||
self.player.lockedScreen = NO;
|
||||
self.lockBtn.selected = NO;
|
||||
if (self.player.orientationObserver.supportInterfaceOrientation & ZFInterfaceOrientationMaskPortrait) {
|
||||
[self.player enterFullScreen:NO animated:YES];
|
||||
}
|
||||
if (self.backBtnClickCallback) {
|
||||
self.backBtnClickCallback();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)playPauseButtonClickAction:(UIButton *)sender {
|
||||
[self playOrPause];
|
||||
}
|
||||
|
||||
/// 根据当前播放状态取反
|
||||
- (void)playOrPause {
|
||||
self.playOrPauseBtn.selected = !self.playOrPauseBtn.isSelected;
|
||||
self.playOrPauseBtn.isSelected? [self.player.currentPlayerManager play]: [self.player.currentPlayerManager pause];
|
||||
}
|
||||
|
||||
- (void)playBtnSelectedState:(BOOL)selected {
|
||||
self.playOrPauseBtn.selected = selected;
|
||||
}
|
||||
|
||||
- (void)lockButtonClickAction:(UIButton *)sender {
|
||||
sender.selected = !sender.selected;
|
||||
self.player.lockedScreen = sender.selected;
|
||||
}
|
||||
|
||||
#pragma mark - ZFSliderViewDelegate
|
||||
|
||||
- (void)sliderTouchBegan:(float)value {
|
||||
self.slider.isdragging = YES;
|
||||
}
|
||||
|
||||
- (void)sliderTouchEnded:(float)value {
|
||||
if (self.player.totalTime > 0) {
|
||||
self.slider.isdragging = YES;
|
||||
if (self.sliderValueChanging) self.sliderValueChanging(value, self.slider.isForward);
|
||||
@zf_weakify(self)
|
||||
[self.player seekToTime:self.player.totalTime*value completionHandler:^(BOOL finished) {
|
||||
@zf_strongify(self)
|
||||
self.slider.isdragging = NO;
|
||||
if (finished) {
|
||||
if (self.sliderValueChanged) self.sliderValueChanged(value);
|
||||
if (self.seekToPlay) {
|
||||
[self.player.currentPlayerManager play];
|
||||
}
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
self.slider.isdragging = NO;
|
||||
self.slider.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sliderValueChanged:(float)value {
|
||||
if (self.player.totalTime == 0) {
|
||||
self.slider.value = 0;
|
||||
return;
|
||||
}
|
||||
self.slider.isdragging = YES;
|
||||
NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
|
||||
self.currentTimeLabel.text = currentTimeString;
|
||||
if (self.sliderValueChanging) self.sliderValueChanging(value,self.slider.isForward);
|
||||
}
|
||||
|
||||
- (void)sliderTapped:(float)value {
|
||||
[self sliderTouchEnded:value];
|
||||
NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
|
||||
self.currentTimeLabel.text = currentTimeString;
|
||||
}
|
||||
|
||||
#pragma mark - public method
|
||||
|
||||
/// 重置ControlView
|
||||
- (void)resetControlView {
|
||||
self.slider.value = 0;
|
||||
self.slider.bufferValue = 0;
|
||||
self.currentTimeLabel.text = @"00:00";
|
||||
self.totalTimeLabel.text = @"00:00";
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.playOrPauseBtn.selected = YES;
|
||||
self.titleLabel.text = @"";
|
||||
self.topToolView.alpha = 1;
|
||||
self.bottomToolView.alpha = 1;
|
||||
self.isShow = NO;
|
||||
self.lockBtn.selected = self.player.isLockedScreen;
|
||||
}
|
||||
|
||||
- (void)showControlView {
|
||||
self.lockBtn.alpha = 1;
|
||||
self.isShow = YES;
|
||||
if (self.player.isLockedScreen) {
|
||||
self.topToolView.zf_y = -self.topToolView.zf_height;
|
||||
self.bottomToolView.zf_y = self.zf_height;
|
||||
} else {
|
||||
self.topToolView.zf_y = 0;
|
||||
self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
|
||||
}
|
||||
self.lockBtn.zf_left = iPhoneX ? 50: 18;
|
||||
self.player.statusBarHidden = NO;
|
||||
if (self.player.isLockedScreen) {
|
||||
self.topToolView.alpha = 0;
|
||||
self.bottomToolView.alpha = 0;
|
||||
} else {
|
||||
self.topToolView.alpha = 1;
|
||||
self.bottomToolView.alpha = 1;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)hideControlView {
|
||||
self.isShow = NO;
|
||||
self.topToolView.zf_y = -self.topToolView.zf_height;
|
||||
self.bottomToolView.zf_y = self.zf_height;
|
||||
self.lockBtn.zf_left = iPhoneX ? -82: -47;
|
||||
self.player.statusBarHidden = YES;
|
||||
self.topToolView.alpha = 0;
|
||||
self.bottomToolView.alpha = 0;
|
||||
self.lockBtn.alpha = 0;
|
||||
}
|
||||
|
||||
- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch {
|
||||
CGRect sliderRect = [self.bottomToolView convertRect:self.slider.frame toView:self];
|
||||
if (CGRectContainsPoint(sliderRect, point)) {
|
||||
return NO;
|
||||
}
|
||||
if (self.player.isLockedScreen && type != ZFPlayerGestureTypeSingleTap) { // 锁定屏幕方向后只相应tap手势
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer presentationSizeChanged:(CGSize)size {
|
||||
self.lockBtn.hidden = self.player.orientationObserver.fullScreenMode == ZFFullScreenModePortrait;
|
||||
}
|
||||
|
||||
/// 视频view即将旋转
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer orientationWillChange:(ZFOrientationObserver *)observer {
|
||||
if (self.showCustomStatusBar) {
|
||||
if (self.hidden) {
|
||||
[self.statusBarView destoryTimer];
|
||||
} else {
|
||||
[self.statusBarView startTimer];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
|
||||
if (!self.slider.isdragging) {
|
||||
NSString *currentTimeString = [ZFUtilities convertTimeSecond:currentTime];
|
||||
self.currentTimeLabel.text = currentTimeString;
|
||||
NSString *totalTimeString = [ZFUtilities convertTimeSecond:totalTime];
|
||||
self.totalTimeLabel.text = totalTimeString;
|
||||
self.slider.value = videoPlayer.progress;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime {
|
||||
self.slider.bufferValue = videoPlayer.bufferProgress;
|
||||
}
|
||||
|
||||
- (void)showTitle:(NSString *)title fullScreenMode:(ZFFullScreenMode)fullScreenMode {
|
||||
self.titleLabel.text = title;
|
||||
self.player.orientationObserver.fullScreenMode = fullScreenMode;
|
||||
self.lockBtn.hidden = fullScreenMode == ZFFullScreenModePortrait;
|
||||
}
|
||||
|
||||
/// 调节播放进度slider和当前时间更新
|
||||
- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString {
|
||||
self.slider.value = value;
|
||||
self.currentTimeLabel.text = timeString;
|
||||
self.slider.isdragging = YES;
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.slider.sliderBtn.transform = CGAffineTransformMakeScale(1.2, 1.2);
|
||||
}];
|
||||
}
|
||||
|
||||
/// 滑杆结束滑动
|
||||
- (void)sliderChangeEnded {
|
||||
self.slider.isdragging = NO;
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.slider.sliderBtn.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (void)setFullScreenMode:(ZFFullScreenMode)fullScreenMode {
|
||||
_fullScreenMode = fullScreenMode;
|
||||
self.player.orientationObserver.fullScreenMode = fullScreenMode;
|
||||
self.lockBtn.hidden = fullScreenMode == ZFFullScreenModePortrait;
|
||||
}
|
||||
|
||||
- (void)setShowCustomStatusBar:(BOOL)showCustomStatusBar {
|
||||
_showCustomStatusBar = showCustomStatusBar;
|
||||
self.statusBarView.hidden = !showCustomStatusBar;
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (ZFPlayerStatusBar *)statusBarView {
|
||||
if (!_statusBarView) {
|
||||
_statusBarView = [[ZFPlayerStatusBar alloc] init];
|
||||
_statusBarView.hidden = YES;
|
||||
}
|
||||
return _statusBarView;
|
||||
}
|
||||
|
||||
- (UIView *)topToolView {
|
||||
if (!_topToolView) {
|
||||
_topToolView = [[UIView alloc] init];
|
||||
UIImage *image = ZFPlayer_Image(@"ZFPlayer_top_shadow");
|
||||
_topToolView.layer.contents = (id)image.CGImage;
|
||||
}
|
||||
return _topToolView;
|
||||
}
|
||||
|
||||
- (UIButton *)backBtn {
|
||||
if (!_backBtn) {
|
||||
_backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_backBtn setImage:ZFPlayer_Image(@"ZFPlayer_back_full") forState:UIControlStateNormal];
|
||||
}
|
||||
return _backBtn;
|
||||
}
|
||||
|
||||
- (UILabel *)titleLabel {
|
||||
if (!_titleLabel) {
|
||||
_titleLabel = [[UILabel alloc] init];
|
||||
_titleLabel.textColor = [UIColor whiteColor];
|
||||
_titleLabel.font = [UIFont systemFontOfSize:15.0];
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
|
||||
- (UIView *)bottomToolView {
|
||||
if (!_bottomToolView) {
|
||||
_bottomToolView = [[UIView alloc] init];
|
||||
UIImage *image = ZFPlayer_Image(@"ZFPlayer_bottom_shadow");
|
||||
_bottomToolView.layer.contents = (id)image.CGImage;
|
||||
}
|
||||
return _bottomToolView;
|
||||
}
|
||||
|
||||
- (UIButton *)playOrPauseBtn {
|
||||
if (!_playOrPauseBtn) {
|
||||
_playOrPauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_playOrPauseBtn setImage:ZFPlayer_Image(@"ZFPlayer_play") forState:UIControlStateNormal];
|
||||
[_playOrPauseBtn setImage:ZFPlayer_Image(@"ZFPlayer_pause") forState:UIControlStateSelected];
|
||||
}
|
||||
return _playOrPauseBtn;
|
||||
}
|
||||
|
||||
- (UILabel *)currentTimeLabel {
|
||||
if (!_currentTimeLabel) {
|
||||
_currentTimeLabel = [[UILabel alloc] init];
|
||||
_currentTimeLabel.textColor = [UIColor whiteColor];
|
||||
_currentTimeLabel.font = [UIFont systemFontOfSize:14.0f];
|
||||
_currentTimeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _currentTimeLabel;
|
||||
}
|
||||
|
||||
- (ZFSliderView *)slider {
|
||||
if (!_slider) {
|
||||
_slider = [[ZFSliderView alloc] init];
|
||||
_slider.delegate = self;
|
||||
_slider.maximumTrackTintColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.8];
|
||||
_slider.bufferTrackTintColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
|
||||
_slider.minimumTrackTintColor = [UIColor whiteColor];
|
||||
[_slider setThumbImage:ZFPlayer_Image(@"ZFPlayer_slider") forState:UIControlStateNormal];
|
||||
_slider.sliderHeight = 2;
|
||||
}
|
||||
return _slider;
|
||||
}
|
||||
|
||||
- (UILabel *)totalTimeLabel {
|
||||
if (!_totalTimeLabel) {
|
||||
_totalTimeLabel = [[UILabel alloc] init];
|
||||
_totalTimeLabel.textColor = [UIColor whiteColor];
|
||||
_totalTimeLabel.font = [UIFont systemFontOfSize:14.0f];
|
||||
_totalTimeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _totalTimeLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)lockBtn {
|
||||
if (!_lockBtn) {
|
||||
_lockBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_lockBtn setImage:ZFPlayer_Image(@"ZFPlayer_unlock-nor") forState:UIControlStateNormal];
|
||||
[_lockBtn setImage:ZFPlayer_Image(@"ZFPlayer_lock-nor") forState:UIControlStateSelected];
|
||||
}
|
||||
return _lockBtn;
|
||||
}
|
||||
|
||||
@end
|
||||
66
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLoadingView.h
generated
Executable file
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// ZFLoadingView.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ZFLoadingType) {
|
||||
ZFLoadingTypeKeep,
|
||||
ZFLoadingTypeFadeOut,
|
||||
};
|
||||
|
||||
@interface ZFLoadingView : UIView
|
||||
|
||||
/// default is ZFLoadingTypeKeep.
|
||||
@property (nonatomic, assign) ZFLoadingType animType;
|
||||
|
||||
/// default is whiteColor.
|
||||
@property (nonatomic, strong, null_resettable) UIColor *lineColor;
|
||||
|
||||
/// Sets the line width of the spinner's circle.
|
||||
@property (nonatomic) CGFloat lineWidth;
|
||||
|
||||
/// Sets whether the view is hidden when not animating.
|
||||
@property (nonatomic) BOOL hidesWhenStopped;
|
||||
|
||||
/// Property indicating the duration of the animation, default is 1.5s.
|
||||
@property (nonatomic, readwrite) NSTimeInterval duration;
|
||||
|
||||
/// anima state
|
||||
@property (nonatomic, assign, readonly, getter=isAnimating) BOOL animating;
|
||||
|
||||
/**
|
||||
* Starts animation of the spinner.
|
||||
*/
|
||||
- (void)startAnimating;
|
||||
|
||||
/**
|
||||
* Stops animation of the spinnner.
|
||||
*/
|
||||
- (void)stopAnimating;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
183
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFLoadingView.m
generated
Executable file
@@ -0,0 +1,183 @@
|
||||
//
|
||||
// ZFLoadingView.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLoadingView.h"
|
||||
|
||||
@interface ZFLoadingView ()
|
||||
|
||||
@property (nonatomic, strong, readonly) CAShapeLayer *shapeLayer;
|
||||
@property (nonatomic, assign, getter=isAnimating) BOOL animating;
|
||||
@property (nonatomic, assign) BOOL strokeShow;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFLoadingView
|
||||
|
||||
@synthesize lineColor = _lineColor;
|
||||
@synthesize shapeLayer = _shapeLayer;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initialize];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super initWithCoder:aDecoder]) {
|
||||
[self initialize];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
[self initialize];
|
||||
}
|
||||
|
||||
- (void)initialize {
|
||||
[self.layer addSublayer:self.shapeLayer];
|
||||
self.duration = 1;
|
||||
self.lineWidth = 1;
|
||||
self.lineColor = [UIColor whiteColor];
|
||||
self.userInteractionEnabled = NO;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
CGFloat width = MIN(self.bounds.size.width, self.bounds.size.height);
|
||||
CGFloat height = width;
|
||||
self.shapeLayer.frame = CGRectMake(0, 0, width, height);
|
||||
|
||||
CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
|
||||
CGFloat radius = MIN(CGRectGetWidth(self.bounds) / 2, CGRectGetHeight(self.bounds) / 2) - self.shapeLayer.lineWidth / 2;
|
||||
CGFloat startAngle = (CGFloat)(0);
|
||||
CGFloat endAngle = (CGFloat)(2*M_PI);
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
|
||||
self.shapeLayer.path = path.CGPath;
|
||||
}
|
||||
|
||||
- (void)startAnimating {
|
||||
if (self.animating) return;
|
||||
self.animating = YES;
|
||||
if (self.animType == ZFLoadingTypeFadeOut) [self fadeOutShow];
|
||||
CABasicAnimation *rotationAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
|
||||
rotationAnim.toValue = [NSNumber numberWithFloat:2 * M_PI];
|
||||
rotationAnim.duration = self.duration;
|
||||
rotationAnim.repeatCount = CGFLOAT_MAX;
|
||||
rotationAnim.removedOnCompletion = NO;
|
||||
[self.shapeLayer addAnimation:rotationAnim forKey:@"rotation"];
|
||||
if (self.hidesWhenStopped) {
|
||||
self.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopAnimating {
|
||||
if (!self.animating) return;
|
||||
self.animating = NO;
|
||||
[self.shapeLayer removeAllAnimations];
|
||||
if (self.hidesWhenStopped) {
|
||||
self.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)fadeOutShow {
|
||||
CABasicAnimation *headAnimation = [CABasicAnimation animation];
|
||||
headAnimation.keyPath = @"strokeStart";
|
||||
headAnimation.duration = self.duration / 1.5f;
|
||||
headAnimation.fromValue = @(0.f);
|
||||
headAnimation.toValue = @(0.25f);
|
||||
|
||||
CABasicAnimation *tailAnimation = [CABasicAnimation animation];
|
||||
tailAnimation.keyPath = @"strokeEnd";
|
||||
tailAnimation.duration = self.duration / 1.5f;
|
||||
tailAnimation.fromValue = @(0.f);
|
||||
tailAnimation.toValue = @(1.f);
|
||||
|
||||
CABasicAnimation *endHeadAnimation = [CABasicAnimation animation];
|
||||
endHeadAnimation.keyPath = @"strokeStart";
|
||||
endHeadAnimation.beginTime = self.duration / 1.5f;
|
||||
endHeadAnimation.duration = self.duration / 3.0f;
|
||||
endHeadAnimation.fromValue = @(0.25f);
|
||||
endHeadAnimation.toValue = @(1.f);
|
||||
|
||||
CABasicAnimation *endTailAnimation = [CABasicAnimation animation];
|
||||
endTailAnimation.keyPath = @"strokeEnd";
|
||||
endTailAnimation.beginTime = self.duration / 1.5f;
|
||||
endTailAnimation.duration = self.duration / 3.0f;
|
||||
endTailAnimation.fromValue = @(1.f);
|
||||
endTailAnimation.toValue = @(1.f);
|
||||
|
||||
CAAnimationGroup *animations = [CAAnimationGroup animation];
|
||||
[animations setDuration:self.duration];
|
||||
[animations setAnimations:@[headAnimation, tailAnimation, endHeadAnimation, endTailAnimation]];
|
||||
animations.repeatCount = INFINITY;
|
||||
animations.removedOnCompletion = NO;
|
||||
[self.shapeLayer addAnimation:animations forKey:@"strokeAnim"];
|
||||
|
||||
if (self.hidesWhenStopped) {
|
||||
self.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - setter and getter
|
||||
|
||||
- (CAShapeLayer *)shapeLayer {
|
||||
if (!_shapeLayer) {
|
||||
_shapeLayer = [CAShapeLayer layer];
|
||||
_shapeLayer.strokeColor = self.lineColor.CGColor;
|
||||
_shapeLayer.fillColor = [UIColor clearColor].CGColor;
|
||||
_shapeLayer.strokeStart = 0.1;
|
||||
_shapeLayer.strokeEnd = 1;
|
||||
_shapeLayer.lineCap = @"round";
|
||||
_shapeLayer.anchorPoint = CGPointMake(0.5, 0.5);
|
||||
}
|
||||
return _shapeLayer;
|
||||
}
|
||||
|
||||
- (UIColor *)lineColor {
|
||||
if (!_lineColor) {
|
||||
return [UIColor whiteColor];
|
||||
}
|
||||
return _lineColor;
|
||||
}
|
||||
|
||||
- (void)setLineWidth:(CGFloat)lineWidth {
|
||||
_lineWidth = lineWidth;
|
||||
self.shapeLayer.lineWidth = lineWidth;
|
||||
}
|
||||
|
||||
- (void)setLineColor:(UIColor *)lineColor {
|
||||
if (!lineColor) return;
|
||||
_lineColor = lineColor;
|
||||
self.shapeLayer.strokeColor = lineColor.CGColor;
|
||||
}
|
||||
|
||||
- (void)setHidesWhenStopped:(BOOL)hidesWhenStopped {
|
||||
_hidesWhenStopped = hidesWhenStopped;
|
||||
self.hidden = !self.isAnimating && hidesWhenStopped;
|
||||
}
|
||||
|
||||
@end
|
||||
39
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFNetworkSpeedMonitor.h
generated
Normal file
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// ZFNetworkSpeedMonitor.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
extern NSString *const ZFDownloadNetworkSpeedNotificationKey;
|
||||
extern NSString *const ZFUploadNetworkSpeedNotificationKey;
|
||||
extern NSString *const ZFNetworkSpeedNotificationKey;
|
||||
|
||||
@interface ZFNetworkSpeedMonitor : NSObject
|
||||
|
||||
@property (nonatomic, copy, readonly) NSString *downloadNetworkSpeed;
|
||||
@property (nonatomic, copy, readonly) NSString *uploadNetworkSpeed;
|
||||
|
||||
- (void)startNetworkSpeedMonitor;
|
||||
- (void)stopNetworkSpeedMonitor;
|
||||
|
||||
@end
|
||||
167
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFNetworkSpeedMonitor.m
generated
Normal file
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// ZFNetworkSpeedMonitor.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFNetworkSpeedMonitor.h"
|
||||
#if __has_include(<ZFPlayer/ZFPlayerLogManager.h>)
|
||||
#import <ZFPlayer/ZFPlayerLogManager.h>
|
||||
#else
|
||||
#import "ZFPlayerLogManager.h"
|
||||
#endif
|
||||
#include <arpa/inet.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
|
||||
NSString *const ZFDownloadNetworkSpeedNotificationKey = @"ZFDownloadNetworkSpeedNotificationKey";
|
||||
NSString *const ZFUploadNetworkSpeedNotificationKey = @"ZFUploadNetworkSpeedNotificationKey";
|
||||
NSString *const ZFNetworkSpeedNotificationKey = @"ZFNetworkSpeedNotificationKey";
|
||||
|
||||
@interface ZFNetworkSpeedMonitor () {
|
||||
// 总网速
|
||||
uint32_t _iBytes;
|
||||
uint32_t _oBytes;
|
||||
uint32_t _allFlow;
|
||||
|
||||
// wifi网速
|
||||
uint32_t _wifiIBytes;
|
||||
uint32_t _wifiOBytes;
|
||||
uint32_t _wifiFlow;
|
||||
|
||||
// 3G网速
|
||||
uint32_t _wwanIBytes;
|
||||
uint32_t _wwanOBytes;
|
||||
uint32_t _wwanFlow;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) NSTimer *timer;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFNetworkSpeedMonitor
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_iBytes = _oBytes = _allFlow = _wifiIBytes = _wifiOBytes = _wifiFlow = _wwanIBytes = _wwanOBytes = _wwanFlow = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// 开始监听网速
|
||||
- (void)startNetworkSpeedMonitor {
|
||||
if (!_timer) {
|
||||
_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(checkNetworkSpeed) userInfo:nil repeats:YES];
|
||||
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
|
||||
[_timer fire];
|
||||
}
|
||||
}
|
||||
|
||||
// 停止监听网速
|
||||
- (void)stopNetworkSpeedMonitor {
|
||||
if ([_timer isValid]) {
|
||||
[_timer invalidate];
|
||||
_timer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)stringWithbytes:(int)bytes {
|
||||
if (bytes < 1024) { // B
|
||||
return [NSString stringWithFormat:@"%dB", bytes];
|
||||
} else if (bytes >= 1024 && bytes < 1024 * 1024) { // KB
|
||||
return [NSString stringWithFormat:@"%.0fKB", (double)bytes / 1024];
|
||||
} else if (bytes >= 1024 * 1024 && bytes < 1024 * 1024 * 1024) { // MB
|
||||
return [NSString stringWithFormat:@"%.1fMB", (double)bytes / (1024 * 1024)];
|
||||
} else { // GB
|
||||
return [NSString stringWithFormat:@"%.1fGB", (double)bytes / (1024 * 1024 * 1024)];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)checkNetworkSpeed {
|
||||
struct ifaddrs *ifa_list = 0, *ifa;
|
||||
if (getifaddrs(&ifa_list) == -1) return;
|
||||
|
||||
uint32_t iBytes = 0;
|
||||
uint32_t oBytes = 0;
|
||||
uint32_t allFlow = 0;
|
||||
uint32_t wifiIBytes = 0;
|
||||
uint32_t wifiOBytes = 0;
|
||||
uint32_t wifiFlow = 0;
|
||||
uint32_t wwanIBytes = 0;
|
||||
uint32_t wwanOBytes = 0;
|
||||
uint32_t wwanFlow = 0;
|
||||
|
||||
for (ifa = ifa_list; ifa; ifa = ifa->ifa_next) {
|
||||
if (AF_LINK != ifa->ifa_addr->sa_family) continue;
|
||||
if (!(ifa->ifa_flags & IFF_UP) && !(ifa->ifa_flags & IFF_RUNNING)) continue;
|
||||
if (ifa->ifa_data == 0) continue;
|
||||
|
||||
// network
|
||||
if (strncmp(ifa->ifa_name, "lo", 2)) {
|
||||
struct if_data* if_data = (struct if_data*)ifa->ifa_data;
|
||||
iBytes += if_data->ifi_ibytes;
|
||||
oBytes += if_data->ifi_obytes;
|
||||
allFlow = iBytes + oBytes;
|
||||
}
|
||||
|
||||
//wifi
|
||||
if (!strcmp(ifa->ifa_name, "en0")) {
|
||||
struct if_data* if_data = (struct if_data*)ifa->ifa_data;
|
||||
wifiIBytes += if_data->ifi_ibytes;
|
||||
wifiOBytes += if_data->ifi_obytes;
|
||||
wifiFlow = wifiIBytes + wifiOBytes;
|
||||
}
|
||||
|
||||
//3G or gprs
|
||||
if (!strcmp(ifa->ifa_name, "pdp_ip0")) {
|
||||
struct if_data* if_data = (struct if_data*)ifa->ifa_data;
|
||||
wwanIBytes += if_data->ifi_ibytes;
|
||||
wwanOBytes += if_data->ifi_obytes;
|
||||
wwanFlow = wwanIBytes + wwanOBytes;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifa_list);
|
||||
if (_iBytes != 0) {
|
||||
_downloadNetworkSpeed = [[self stringWithbytes:iBytes - _iBytes] stringByAppendingString:@"/s"];
|
||||
NSMutableDictionary *userInfo = @{}.mutableCopy;
|
||||
userInfo[ZFNetworkSpeedNotificationKey] = _downloadNetworkSpeed;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ZFDownloadNetworkSpeedNotificationKey object:nil userInfo:userInfo];
|
||||
ZFPlayerLog(@"downloadNetworkSpeed : %@",_downloadNetworkSpeed);
|
||||
}
|
||||
|
||||
_iBytes = iBytes;
|
||||
|
||||
if (_oBytes != 0) {
|
||||
_uploadNetworkSpeed = [[self stringWithbytes:oBytes - _oBytes] stringByAppendingString:@"/s"];
|
||||
NSMutableDictionary *userInfo = @{}.mutableCopy;
|
||||
userInfo[ZFNetworkSpeedNotificationKey] = _uploadNetworkSpeed;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:ZFUploadNetworkSpeedNotificationKey object:nil userInfo:userInfo];
|
||||
ZFPlayerLog(@"uploadNetworkSpeed :%@",_uploadNetworkSpeed);
|
||||
}
|
||||
|
||||
_oBytes = oBytes;
|
||||
}
|
||||
|
||||
@end
|
||||
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_back_full@2x.png
generated
Normal file
|
After Width: | Height: | Size: 339 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_back_full@3x.png
generated
Normal file
|
After Width: | Height: | Size: 513 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_battery_lightning.png
generated
Normal file
|
After Width: | Height: | Size: 572 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_bottom_shadow.png
generated
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_high@2x.png
generated
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_high@3x.png
generated
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_low@2x.png
generated
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_brightness_low@3x.png
generated
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_close@2x.png
generated
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_close@3x.png
generated
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_closeWatch@2x.png
generated
Normal file
|
After Width: | Height: | Size: 761 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_closeWatch@3x.png
generated
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_backward@2x.png
generated
Normal file
|
After Width: | Height: | Size: 615 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_backward@3x.png
generated
Normal file
|
After Width: | Height: | Size: 834 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_forward@2x.png
generated
Normal file
|
After Width: | Height: | Size: 565 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fast_forward@3x.png
generated
Normal file
|
After Width: | Height: | Size: 772 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fullscreen@2x.png
generated
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_fullscreen@3x.png
generated
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_lock-nor@2x.png
generated
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_lock-nor@3x.png
generated
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_muted@2x.png
generated
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_muted@3x.png
generated
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_next@2x.png
generated
Normal file
|
After Width: | Height: | Size: 407 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_next@3x.png
generated
Normal file
|
After Width: | Height: | Size: 585 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_pause@2x.png
generated
Normal file
|
After Width: | Height: | Size: 168 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_pause@3x.png
generated
Normal file
|
After Width: | Height: | Size: 188 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_play@2x.png
generated
Normal file
|
After Width: | Height: | Size: 453 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_play@3x.png
generated
Normal file
|
After Width: | Height: | Size: 660 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_shrinkscreen@2x.png
generated
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_shrinkscreen@3x.png
generated
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_slider.png
generated
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_slider@2x.png
generated
Normal file
|
After Width: | Height: | Size: 577 B |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_slider@3x.png
generated
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_top_shadow.png
generated
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_unlock-nor@2x.png
generated
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_unlock-nor@3x.png
generated
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_high@2x.png
generated
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_high@3x.png
generated
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_low@2x.png
generated
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/ZFPlayer_volume_low@3x.png
generated
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPause_44x44_@2x.png
generated
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPause_44x44_@3x.png
generated
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPlay_44x44_@2x.png
generated
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayer.bundle/new_allPlay_44x44_@3x.png
generated
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
154
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayerControlView.h
generated
Executable file
@@ -0,0 +1,154 @@
|
||||
//
|
||||
// ZFPlayerControlView.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ZFPortraitControlView.h"
|
||||
#import "ZFLandScapeControlView.h"
|
||||
#import "ZFSpeedLoadingView.h"
|
||||
#import "ZFSmallFloatControlView.h"
|
||||
#if __has_include(<ZFPlayer/ZFPlayerMediaControl.h>)
|
||||
#import <ZFPlayer/ZFPlayerMediaControl.h>
|
||||
#else
|
||||
#import "ZFPlayerMediaControl.h"
|
||||
#endif
|
||||
|
||||
@interface ZFPlayerControlView : UIView <ZFPlayerMediaControl>
|
||||
|
||||
/// 竖屏控制层的View
|
||||
@property (nonatomic, strong, readonly) ZFPortraitControlView *portraitControlView;
|
||||
|
||||
/// 横屏控制层的View
|
||||
@property (nonatomic, strong, readonly) ZFLandScapeControlView *landScapeControlView;
|
||||
|
||||
/// 加载loading
|
||||
@property (nonatomic, strong, readonly) ZFSpeedLoadingView *activity;
|
||||
|
||||
/// 快进快退View
|
||||
@property (nonatomic, strong, readonly) UIView *fastView;
|
||||
|
||||
/// 快进快退进度progress
|
||||
@property (nonatomic, strong, readonly) ZFSliderView *fastProgressView;
|
||||
|
||||
/// 快进快退时间
|
||||
@property (nonatomic, strong, readonly) UILabel *fastTimeLabel;
|
||||
|
||||
/// 快进快退ImageView
|
||||
@property (nonatomic, strong, readonly) UIImageView *fastImageView;
|
||||
|
||||
/// 加载失败按钮
|
||||
@property (nonatomic, strong, readonly) UIButton *failBtn;
|
||||
|
||||
/// 底部播放进度
|
||||
@property (nonatomic, strong, readonly) ZFSliderView *bottomPgrogress;
|
||||
|
||||
/// 封面图
|
||||
@property (nonatomic, strong, readonly) UIImageView *coverImageView;
|
||||
|
||||
/// 高斯模糊的背景图
|
||||
@property (nonatomic, strong, readonly) UIImageView *bgImgView;
|
||||
|
||||
/// 高斯模糊视图
|
||||
@property (nonatomic, strong, readonly) UIView *effectView;
|
||||
|
||||
/// 小窗口控制层
|
||||
@property (nonatomic, strong, readonly) ZFSmallFloatControlView *floatControlView;
|
||||
|
||||
/// 快进视图是否显示动画,默认NO.
|
||||
@property (nonatomic, assign) BOOL fastViewAnimated;
|
||||
|
||||
/// 视频之外区域是否高斯模糊显示,默认YES.
|
||||
@property (nonatomic, assign) BOOL effectViewShow;
|
||||
|
||||
/// 如果是暂停状态,seek完是否播放,默认YES
|
||||
@property (nonatomic, assign) BOOL seekToPlay;
|
||||
|
||||
/// 返回按钮点击回调
|
||||
@property (nonatomic, copy) void(^backBtnClickCallback)(void);
|
||||
|
||||
/// 控制层显示或者隐藏
|
||||
@property (nonatomic, readonly) BOOL controlViewAppeared;
|
||||
|
||||
/// 控制层显示或者隐藏的回调
|
||||
@property (nonatomic, copy) void(^controlViewAppearedCallback)(BOOL appeared);
|
||||
|
||||
/// 控制层自动隐藏的时间,默认2.5秒
|
||||
@property (nonatomic, assign) NSTimeInterval autoHiddenTimeInterval;
|
||||
|
||||
/// 控制层显示、隐藏动画的时长,默认0.25秒
|
||||
@property (nonatomic, assign) NSTimeInterval autoFadeTimeInterval;
|
||||
|
||||
/// 横向滑动控制播放进度时是否显示控制层,默认 YES.
|
||||
@property (nonatomic, assign) BOOL horizontalPanShowControlView;
|
||||
|
||||
/// prepare时候是否显示控制层,默认 NO.
|
||||
@property (nonatomic, assign) BOOL prepareShowControlView;
|
||||
|
||||
/// prepare时候是否显示loading,默认 NO.
|
||||
@property (nonatomic, assign) BOOL prepareShowLoading;
|
||||
|
||||
/// 是否自定义禁止pan手势,默认 NO.
|
||||
@property (nonatomic, assign) BOOL customDisablePanMovingDirection;
|
||||
|
||||
/// 横屏时候是否显示自定义状态栏(iOS13+),默认 NO.
|
||||
@property (nonatomic, assign) BOOL showCustomStatusBar;
|
||||
|
||||
/// 全屏模式
|
||||
@property (nonatomic, assign) ZFFullScreenMode fullScreenMode;
|
||||
|
||||
/**
|
||||
设置标题、封面、全屏模式
|
||||
|
||||
@param title 视频的标题
|
||||
@param coverUrl 视频的封面,占位图默认是灰色的
|
||||
@param fullScreenMode 全屏模式
|
||||
*/
|
||||
- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl fullScreenMode:(ZFFullScreenMode)fullScreenMode;
|
||||
|
||||
/**
|
||||
设置标题、封面、默认占位图、全屏模式
|
||||
|
||||
@param title 视频的标题
|
||||
@param coverUrl 视频的封面
|
||||
@param placeholder 指定封面的placeholder
|
||||
@param fullScreenMode 全屏模式
|
||||
*/
|
||||
- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl placeholderImage:(UIImage *)placeholder fullScreenMode:(ZFFullScreenMode)fullScreenMode;
|
||||
|
||||
/**
|
||||
设置标题、UIImage封面、全屏模式
|
||||
|
||||
@param title 视频的标题
|
||||
@param image 视频的封面UIImage
|
||||
@param fullScreenMode 全屏模式
|
||||
*/
|
||||
- (void)showTitle:(NSString *)title coverImage:(UIImage *)image fullScreenMode:(ZFFullScreenMode)fullScreenMode;
|
||||
|
||||
//- (void)showFullScreen
|
||||
|
||||
/**
|
||||
重置控制层
|
||||
*/
|
||||
- (void)resetControlView;
|
||||
|
||||
@end
|
||||
831
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayerControlView.m
generated
Executable file
@@ -0,0 +1,831 @@
|
||||
//
|
||||
// ZFPlayerControlView.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFPlayerControlView.h"
|
||||
#import <AVKit/AVKit.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import "UIView+ZFFrame.h"
|
||||
#import "ZFSliderView.h"
|
||||
#import "ZFUtilities.h"
|
||||
#import "UIImageView+ZFCache.h"
|
||||
#import <MediaPlayer/MediaPlayer.h>
|
||||
#import "ZFVolumeBrightnessView.h"
|
||||
#if __has_include(<ZFPlayer/ZFPlayer.h>)
|
||||
#import <ZFPlayer/ZFPlayerConst.h>
|
||||
#else
|
||||
#import "ZFPlayerConst.h"
|
||||
#endif
|
||||
|
||||
|
||||
@interface ZFPlayerControlView () <ZFSliderViewDelegate>
|
||||
/// 竖屏控制层的View
|
||||
@property (nonatomic, strong) ZFPortraitControlView *portraitControlView;
|
||||
/// 横屏控制层的View
|
||||
@property (nonatomic, strong) ZFLandScapeControlView *landScapeControlView;
|
||||
/// 加载loading
|
||||
@property (nonatomic, strong) ZFSpeedLoadingView *activity;
|
||||
/// 快进快退View
|
||||
@property (nonatomic, strong) UIView *fastView;
|
||||
/// 快进快退进度progress
|
||||
@property (nonatomic, strong) ZFSliderView *fastProgressView;
|
||||
/// 快进快退时间
|
||||
@property (nonatomic, strong) UILabel *fastTimeLabel;
|
||||
/// 快进快退ImageView
|
||||
@property (nonatomic, strong) UIImageView *fastImageView;
|
||||
/// 加载失败按钮
|
||||
@property (nonatomic, strong) UIButton *failBtn;
|
||||
/// 底部播放进度
|
||||
@property (nonatomic, strong) ZFSliderView *bottomPgrogress;
|
||||
/// 是否显示了控制层
|
||||
@property (nonatomic, assign, getter=isShowing) BOOL showing;
|
||||
/// 是否播放结束
|
||||
@property (nonatomic, assign, getter=isPlayEnd) BOOL playeEnd;
|
||||
|
||||
@property (nonatomic, assign) BOOL controlViewAppeared;
|
||||
|
||||
@property (nonatomic, assign) NSTimeInterval sumTime;
|
||||
|
||||
@property (nonatomic, strong) dispatch_block_t afterBlock;
|
||||
|
||||
@property (nonatomic, strong) ZFSmallFloatControlView *floatControlView;
|
||||
|
||||
@property (nonatomic, strong) ZFVolumeBrightnessView *volumeBrightnessView;
|
||||
|
||||
@property (nonatomic, strong) UIImageView *bgImgView;
|
||||
|
||||
@property (nonatomic, strong) UIView *effectView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFPlayerControlView
|
||||
@synthesize player = _player;
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self addAllSubViews];
|
||||
self.landScapeControlView.hidden = YES;
|
||||
self.floatControlView.hidden = YES;
|
||||
self.seekToPlay = YES;
|
||||
self.effectViewShow = YES;
|
||||
self.horizontalPanShowControlView = YES;
|
||||
self.autoFadeTimeInterval = 0.25;
|
||||
self.autoHiddenTimeInterval = 2.5;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(volumeChanged:)
|
||||
name:@"AVSystemController_SystemVolumeDidChangeNotification"
|
||||
object:nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
CGFloat min_x = 0;
|
||||
CGFloat min_y = 0;
|
||||
CGFloat min_w = 0;
|
||||
CGFloat min_h = 0;
|
||||
CGFloat min_view_w = self.zf_width;
|
||||
CGFloat min_view_h = self.zf_height;
|
||||
|
||||
self.portraitControlView.frame = self.bounds;
|
||||
self.landScapeControlView.frame = self.bounds;
|
||||
self.floatControlView.frame = self.bounds;
|
||||
self.coverImageView.frame = self.bounds;
|
||||
self.bgImgView.frame = self.bounds;
|
||||
self.effectView.frame = self.bounds;
|
||||
|
||||
min_w = 80;
|
||||
min_h = 80;
|
||||
self.activity.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.activity.zf_centerX = self.zf_centerX;
|
||||
self.activity.zf_centerY = self.zf_centerY + 10;
|
||||
|
||||
min_w = 150;
|
||||
min_h = 30;
|
||||
self.failBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.failBtn.center = self.center;
|
||||
|
||||
min_w = 140;
|
||||
min_h = 80;
|
||||
self.fastView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.fastView.center = self.center;
|
||||
|
||||
min_w = 32;
|
||||
min_x = (self.fastView.zf_width - min_w) / 2;
|
||||
min_y = 5;
|
||||
min_h = 32;
|
||||
self.fastImageView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = 0;
|
||||
min_y = self.fastImageView.zf_bottom + 2;
|
||||
min_w = self.fastView.zf_width;
|
||||
min_h = 20;
|
||||
self.fastTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = 12;
|
||||
min_y = self.fastTimeLabel.zf_bottom + 5;
|
||||
min_w = self.fastView.zf_width - 2 * min_x;
|
||||
min_h = 10;
|
||||
self.fastProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = 0;
|
||||
min_y = min_view_h - 1;
|
||||
min_w = min_view_w;
|
||||
min_h = 1;
|
||||
self.bottomPgrogress.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = 0;
|
||||
min_y = iPhoneX ? 54 : 30;
|
||||
min_w = 170;
|
||||
min_h = 35;
|
||||
self.volumeBrightnessView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.volumeBrightnessView.zf_centerX = self.zf_centerX;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVSystemController_SystemVolumeDidChangeNotification" object:nil];
|
||||
[self cancelAutoFadeOutControlView];
|
||||
}
|
||||
|
||||
/// 添加所有子控件
|
||||
- (void)addAllSubViews {
|
||||
[self addSubview:self.portraitControlView];
|
||||
[self addSubview:self.landScapeControlView];
|
||||
[self addSubview:self.floatControlView];
|
||||
[self addSubview:self.activity];
|
||||
[self addSubview:self.failBtn];
|
||||
[self addSubview:self.fastView];
|
||||
[self.fastView addSubview:self.fastImageView];
|
||||
[self.fastView addSubview:self.fastTimeLabel];
|
||||
[self.fastView addSubview:self.fastProgressView];
|
||||
[self addSubview:self.bottomPgrogress];
|
||||
[self addSubview:self.volumeBrightnessView];
|
||||
}
|
||||
|
||||
- (void)autoFadeOutControlView {
|
||||
self.controlViewAppeared = YES;
|
||||
[self cancelAutoFadeOutControlView];
|
||||
@zf_weakify(self)
|
||||
self.afterBlock = dispatch_block_create(0, ^{
|
||||
@zf_strongify(self)
|
||||
[self hideControlViewWithAnimated:YES];
|
||||
});
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.autoHiddenTimeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(),self.afterBlock);
|
||||
}
|
||||
|
||||
/// 取消延时隐藏controlView的方法
|
||||
- (void)cancelAutoFadeOutControlView {
|
||||
if (self.afterBlock) {
|
||||
dispatch_block_cancel(self.afterBlock);
|
||||
self.afterBlock = nil;
|
||||
}
|
||||
}
|
||||
|
||||
/// 隐藏控制层
|
||||
- (void)hideControlViewWithAnimated:(BOOL)animated {
|
||||
self.controlViewAppeared = NO;
|
||||
if (self.controlViewAppearedCallback) {
|
||||
self.controlViewAppearedCallback(NO);
|
||||
}
|
||||
[UIView animateWithDuration:animated ? self.autoFadeTimeInterval : 0 animations:^{
|
||||
if (self.player.isFullScreen) {
|
||||
[self.landScapeControlView hideControlView];
|
||||
} else {
|
||||
if (!self.player.isSmallFloatViewShow) {
|
||||
[self.portraitControlView hideControlView];
|
||||
}
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
self.bottomPgrogress.hidden = NO;
|
||||
}];
|
||||
}
|
||||
|
||||
/// 显示控制层
|
||||
- (void)showControlViewWithAnimated:(BOOL)animated {
|
||||
self.controlViewAppeared = YES;
|
||||
if (self.controlViewAppearedCallback) {
|
||||
self.controlViewAppearedCallback(YES);
|
||||
}
|
||||
[self autoFadeOutControlView];
|
||||
[UIView animateWithDuration:animated ? self.autoFadeTimeInterval : 0 animations:^{
|
||||
if (self.player.isFullScreen) {
|
||||
[self.landScapeControlView showControlView];
|
||||
} else {
|
||||
if (!self.player.isSmallFloatViewShow) {
|
||||
[self.portraitControlView showControlView];
|
||||
}
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
self.bottomPgrogress.hidden = YES;
|
||||
}];
|
||||
}
|
||||
|
||||
/// 音量改变的通知
|
||||
- (void)volumeChanged:(NSNotification *)notification {
|
||||
NSDictionary *userInfo = notification.userInfo;
|
||||
NSString *reasonstr = userInfo[@"AVSystemController_AudioVolumeChangeReasonNotificationParameter"];
|
||||
if ([reasonstr isEqualToString:@"ExplicitVolumeChange"]) {
|
||||
float volume = [ userInfo[@"AVSystemController_AudioVolumeNotificationParameter"] floatValue];
|
||||
if (self.player.isFullScreen) {
|
||||
[self.volumeBrightnessView updateProgress:volume withVolumeBrightnessType:ZFVolumeBrightnessTypeVolume];
|
||||
} else {
|
||||
[self.volumeBrightnessView addSystemVolumeView];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Public Method
|
||||
|
||||
/// 重置控制层
|
||||
- (void)resetControlView {
|
||||
[self.portraitControlView resetControlView];
|
||||
[self.landScapeControlView resetControlView];
|
||||
[self cancelAutoFadeOutControlView];
|
||||
self.bottomPgrogress.value = 0;
|
||||
self.bottomPgrogress.bufferValue = 0;
|
||||
self.floatControlView.hidden = YES;
|
||||
self.failBtn.hidden = YES;
|
||||
self.volumeBrightnessView.hidden = YES;
|
||||
self.portraitControlView.hidden = self.player.isFullScreen;
|
||||
self.landScapeControlView.hidden = !self.player.isFullScreen;
|
||||
if (self.controlViewAppeared) {
|
||||
[self showControlViewWithAnimated:NO];
|
||||
} else {
|
||||
[self hideControlViewWithAnimated:NO];
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置标题、封面、全屏模式
|
||||
- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl fullScreenMode:(ZFFullScreenMode)fullScreenMode {
|
||||
UIImage *placeholder = [ZFUtilities imageWithColor:[UIColor colorWithRed:220/255.0 green:220/255.0 blue:220/255.0 alpha:1] size:self.bgImgView.bounds.size];
|
||||
[self showTitle:title coverURLString:coverUrl placeholderImage:placeholder fullScreenMode:fullScreenMode];
|
||||
}
|
||||
|
||||
/// 设置标题、封面、默认占位图、全屏模式
|
||||
- (void)showTitle:(NSString *)title coverURLString:(NSString *)coverUrl placeholderImage:(UIImage *)placeholder fullScreenMode:(ZFFullScreenMode)fullScreenMode {
|
||||
[self resetControlView];
|
||||
[self layoutIfNeeded];
|
||||
[self setNeedsDisplay];
|
||||
[self.portraitControlView showTitle:title fullScreenMode:fullScreenMode];
|
||||
[self.landScapeControlView showTitle:title fullScreenMode:fullScreenMode];
|
||||
/// 这里直接设置播放器视图里的coverImageView
|
||||
[self.player.currentPlayerManager.view.coverImageView setImageWithURLString:coverUrl placeholder:placeholder];
|
||||
[self.bgImgView setImageWithURLString:coverUrl placeholder:placeholder];
|
||||
if (self.prepareShowControlView) {
|
||||
[self showControlViewWithAnimated:NO];
|
||||
} else {
|
||||
[self hideControlViewWithAnimated:NO];
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置标题、UIImage封面、全屏模式
|
||||
- (void)showTitle:(NSString *)title coverImage:(UIImage *)image fullScreenMode:(ZFFullScreenMode)fullScreenMode {
|
||||
[self resetControlView];
|
||||
[self layoutIfNeeded];
|
||||
[self setNeedsDisplay];
|
||||
[self.portraitControlView showTitle:title fullScreenMode:fullScreenMode];
|
||||
[self.landScapeControlView showTitle:title fullScreenMode:fullScreenMode];
|
||||
self.coverImageView.image = image;
|
||||
self.bgImgView.image = image;
|
||||
if (self.prepareShowControlView) {
|
||||
[self showControlViewWithAnimated:NO];
|
||||
} else {
|
||||
[self hideControlViewWithAnimated:NO];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - ZFPlayerControlViewDelegate
|
||||
|
||||
/// 手势筛选,返回NO不响应该手势
|
||||
- (BOOL)gestureTriggerCondition:(ZFPlayerGestureControl *)gestureControl gestureType:(ZFPlayerGestureType)gestureType gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer touch:(nonnull UITouch *)touch {
|
||||
CGPoint point = [touch locationInView:self];
|
||||
if (self.player.isSmallFloatViewShow && !self.player.isFullScreen && gestureType != ZFPlayerGestureTypeSingleTap) {
|
||||
return NO;
|
||||
}
|
||||
if (self.player.isFullScreen) {
|
||||
if (!self.customDisablePanMovingDirection) {
|
||||
/// 不禁用滑动方向
|
||||
self.player.disablePanMovingDirection = ZFPlayerDisablePanMovingDirectionNone;
|
||||
}
|
||||
return [self.landScapeControlView shouldResponseGestureWithPoint:point withGestureType:gestureType touch:touch];
|
||||
} else {
|
||||
if (!self.customDisablePanMovingDirection) {
|
||||
if (self.player.scrollView) { /// 列表时候禁止上下滑动(防止和列表滑动冲突)
|
||||
self.player.disablePanMovingDirection = ZFPlayerDisablePanMovingDirectionVertical;
|
||||
} else { /// 不禁用滑动方向
|
||||
self.player.disablePanMovingDirection = ZFPlayerDisablePanMovingDirectionNone;
|
||||
}
|
||||
}
|
||||
return [self.portraitControlView shouldResponseGestureWithPoint:point withGestureType:gestureType touch:touch];
|
||||
}
|
||||
}
|
||||
|
||||
/// 单击手势事件
|
||||
- (void)gestureSingleTapped:(ZFPlayerGestureControl *)gestureControl {
|
||||
if (!self.player) return;
|
||||
if (self.player.isSmallFloatViewShow && !self.player.isFullScreen) {
|
||||
[self.player enterFullScreen:YES animated:YES];
|
||||
} else {
|
||||
if (self.controlViewAppeared) {
|
||||
[self hideControlViewWithAnimated:YES];
|
||||
} else {
|
||||
[self showControlViewWithAnimated:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 双击手势事件
|
||||
- (void)gestureDoubleTapped:(ZFPlayerGestureControl *)gestureControl {
|
||||
if (self.player.isFullScreen) {
|
||||
[self.landScapeControlView playOrPause];
|
||||
} else {
|
||||
[self.portraitControlView playOrPause];
|
||||
}
|
||||
}
|
||||
|
||||
/// 开始滑动手势事件
|
||||
- (void)gestureBeganPan:(ZFPlayerGestureControl *)gestureControl panDirection:(ZFPanDirection)direction panLocation:(ZFPanLocation)location {
|
||||
if (direction == ZFPanDirectionH) {
|
||||
self.sumTime = self.player.currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
/// 滑动中手势事件
|
||||
- (void)gestureChangedPan:(ZFPlayerGestureControl *)gestureControl panDirection:(ZFPanDirection)direction panLocation:(ZFPanLocation)location withVelocity:(CGPoint)velocity {
|
||||
if (direction == ZFPanDirectionH) {
|
||||
// 每次滑动需要叠加时间
|
||||
self.sumTime += velocity.x / 200;
|
||||
// 需要限定sumTime的范围
|
||||
NSTimeInterval totalMovieDuration = self.player.totalTime;
|
||||
if (totalMovieDuration == 0) return;
|
||||
if (self.sumTime > totalMovieDuration) self.sumTime = totalMovieDuration;
|
||||
if (self.sumTime < 0) self.sumTime = 0;
|
||||
BOOL style = NO;
|
||||
if (velocity.x > 0) style = YES;
|
||||
if (velocity.x < 0) style = NO;
|
||||
if (velocity.x == 0) return;
|
||||
[self sliderValueChangingValue:self.sumTime/totalMovieDuration isForward:style];
|
||||
} else if (direction == ZFPanDirectionV) {
|
||||
if (location == ZFPanLocationLeft) { /// 调节亮度
|
||||
self.player.brightness -= (velocity.y) / 10000;
|
||||
[self.volumeBrightnessView updateProgress:self.player.brightness withVolumeBrightnessType:ZFVolumeBrightnessTypeumeBrightness];
|
||||
} else if (location == ZFPanLocationRight) { /// 调节声音
|
||||
self.player.volume -= (velocity.y) / 10000;
|
||||
if (self.player.isFullScreen) {
|
||||
[self.volumeBrightnessView updateProgress:self.player.volume withVolumeBrightnessType:ZFVolumeBrightnessTypeVolume];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 滑动结束手势事件
|
||||
- (void)gestureEndedPan:(ZFPlayerGestureControl *)gestureControl panDirection:(ZFPanDirection)direction panLocation:(ZFPanLocation)location {
|
||||
@zf_weakify(self)
|
||||
if (direction == ZFPanDirectionH && self.sumTime >= 0 && self.player.totalTime > 0) {
|
||||
[self.player seekToTime:self.sumTime completionHandler:^(BOOL finished) {
|
||||
if (finished) {
|
||||
@zf_strongify(self)
|
||||
/// 左右滑动调节播放进度
|
||||
[self.portraitControlView sliderChangeEnded];
|
||||
[self.landScapeControlView sliderChangeEnded];
|
||||
self.bottomPgrogress.isdragging = NO;
|
||||
if (self.controlViewAppeared) {
|
||||
[self autoFadeOutControlView];
|
||||
}
|
||||
}
|
||||
}];
|
||||
if (self.seekToPlay) {
|
||||
[self.player.currentPlayerManager play];
|
||||
}
|
||||
self.sumTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// 捏合手势事件,这里改变了视频的填充模式
|
||||
- (void)gesturePinched:(ZFPlayerGestureControl *)gestureControl scale:(float)scale {
|
||||
if (scale > 1) {
|
||||
self.player.currentPlayerManager.scalingMode = ZFPlayerScalingModeAspectFill;
|
||||
} else {
|
||||
self.player.currentPlayerManager.scalingMode = ZFPlayerScalingModeAspectFit;
|
||||
}
|
||||
}
|
||||
|
||||
/// 准备播放
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer prepareToPlay:(NSURL *)assetURL {
|
||||
[self hideControlViewWithAnimated:NO];
|
||||
}
|
||||
|
||||
/// 播放状态改变
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer playStateChanged:(ZFPlayerPlaybackState)state {
|
||||
if (state == ZFPlayerPlayStatePlaying) {
|
||||
[self.portraitControlView playBtnSelectedState:YES];
|
||||
[self.landScapeControlView playBtnSelectedState:YES];
|
||||
self.failBtn.hidden = YES;
|
||||
/// 开始播放时候判断是否显示loading
|
||||
if (videoPlayer.currentPlayerManager.loadState == ZFPlayerLoadStateStalled && !self.prepareShowLoading) {
|
||||
[self.activity startAnimating];
|
||||
} else if ((videoPlayer.currentPlayerManager.loadState == ZFPlayerLoadStateStalled || videoPlayer.currentPlayerManager.loadState == ZFPlayerLoadStatePrepare) && self.prepareShowLoading) {
|
||||
[self.activity startAnimating];
|
||||
}
|
||||
} else if (state == ZFPlayerPlayStatePaused) {
|
||||
[self.portraitControlView playBtnSelectedState:NO];
|
||||
[self.landScapeControlView playBtnSelectedState:NO];
|
||||
/// 暂停的时候隐藏loading
|
||||
[self.activity stopAnimating];
|
||||
self.failBtn.hidden = YES;
|
||||
} else if (state == ZFPlayerPlayStatePlayFailed) {
|
||||
self.failBtn.hidden = NO;
|
||||
[self.activity stopAnimating];
|
||||
}
|
||||
}
|
||||
|
||||
/// 加载状态改变
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer loadStateChanged:(ZFPlayerLoadState)state {
|
||||
if (state == ZFPlayerLoadStatePrepare) {
|
||||
self.coverImageView.hidden = NO;
|
||||
[self.portraitControlView playBtnSelectedState:videoPlayer.currentPlayerManager.shouldAutoPlay];
|
||||
[self.landScapeControlView playBtnSelectedState:videoPlayer.currentPlayerManager.shouldAutoPlay];
|
||||
} else if (state == ZFPlayerLoadStatePlaythroughOK || state == ZFPlayerLoadStatePlayable) {
|
||||
self.coverImageView.hidden = YES;
|
||||
if (self.effectViewShow) {
|
||||
self.effectView.hidden = NO;
|
||||
} else {
|
||||
self.effectView.hidden = YES;
|
||||
self.player.currentPlayerManager.view.backgroundColor = [UIColor blackColor];
|
||||
}
|
||||
}
|
||||
if (state == ZFPlayerLoadStateStalled && videoPlayer.currentPlayerManager.isPlaying && !self.prepareShowLoading) {
|
||||
[self.activity startAnimating];
|
||||
} else if ((state == ZFPlayerLoadStateStalled || state == ZFPlayerLoadStatePrepare) && videoPlayer.currentPlayerManager.isPlaying && self.prepareShowLoading) {
|
||||
[self.activity startAnimating];
|
||||
} else {
|
||||
[self.activity stopAnimating];
|
||||
}
|
||||
}
|
||||
|
||||
/// 播放进度改变回调
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
|
||||
[self.portraitControlView videoPlayer:videoPlayer currentTime:currentTime totalTime:totalTime];
|
||||
[self.landScapeControlView videoPlayer:videoPlayer currentTime:currentTime totalTime:totalTime];
|
||||
if (!self.bottomPgrogress.isdragging) {
|
||||
self.bottomPgrogress.value = videoPlayer.progress;
|
||||
}
|
||||
}
|
||||
|
||||
/// 缓冲改变回调
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime {
|
||||
[self.portraitControlView videoPlayer:videoPlayer bufferTime:bufferTime];
|
||||
[self.landScapeControlView videoPlayer:videoPlayer bufferTime:bufferTime];
|
||||
self.bottomPgrogress.bufferValue = videoPlayer.bufferProgress;
|
||||
}
|
||||
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer presentationSizeChanged:(CGSize)size {
|
||||
[self.landScapeControlView videoPlayer:videoPlayer presentationSizeChanged:size];
|
||||
}
|
||||
|
||||
/// 视频view即将旋转
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer orientationWillChange:(ZFOrientationObserver *)observer {
|
||||
self.portraitControlView.hidden = observer.isFullScreen;
|
||||
self.landScapeControlView.hidden = !observer.isFullScreen;
|
||||
if (videoPlayer.isSmallFloatViewShow) {
|
||||
self.floatControlView.hidden = observer.isFullScreen;
|
||||
self.portraitControlView.hidden = YES;
|
||||
if (observer.isFullScreen) {
|
||||
self.controlViewAppeared = NO;
|
||||
[self cancelAutoFadeOutControlView];
|
||||
}
|
||||
}
|
||||
if (self.controlViewAppeared) {
|
||||
[self showControlViewWithAnimated:NO];
|
||||
} else {
|
||||
[self hideControlViewWithAnimated:NO];
|
||||
}
|
||||
|
||||
if (observer.isFullScreen) {
|
||||
[self.volumeBrightnessView removeSystemVolumeView];
|
||||
} else {
|
||||
[self.volumeBrightnessView addSystemVolumeView];
|
||||
}
|
||||
[self.landScapeControlView videoPlayer:videoPlayer orientationWillChange:observer];
|
||||
}
|
||||
|
||||
/// 锁定旋转方向
|
||||
- (void)lockedVideoPlayer:(ZFPlayerController *)videoPlayer lockedScreen:(BOOL)locked {
|
||||
[self showControlViewWithAnimated:YES];
|
||||
}
|
||||
|
||||
/// 列表滑动时视频view已经显示
|
||||
- (void)playerDidAppearInScrollView:(ZFPlayerController *)videoPlayer {
|
||||
if (!self.player.stopWhileNotVisible && !videoPlayer.isFullScreen) {
|
||||
self.floatControlView.hidden = YES;
|
||||
self.portraitControlView.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
/// 列表滑动时视频view已经消失
|
||||
- (void)playerDidDisappearInScrollView:(ZFPlayerController *)videoPlayer {
|
||||
if (!self.player.stopWhileNotVisible && !videoPlayer.isFullScreen) {
|
||||
self.floatControlView.hidden = NO;
|
||||
self.portraitControlView.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer floatViewShow:(BOOL)show {
|
||||
self.floatControlView.hidden = !show;
|
||||
self.portraitControlView.hidden = show;
|
||||
}
|
||||
|
||||
#pragma mark - Private Method
|
||||
|
||||
- (void)sliderValueChangingValue:(CGFloat)value isForward:(BOOL)forward {
|
||||
if (self.horizontalPanShowControlView) {
|
||||
/// 显示控制层
|
||||
[self showControlViewWithAnimated:NO];
|
||||
[self cancelAutoFadeOutControlView];
|
||||
}
|
||||
|
||||
self.fastProgressView.value = value;
|
||||
self.fastView.hidden = NO;
|
||||
self.fastView.alpha = 1;
|
||||
if (forward) {
|
||||
self.fastImageView.image = ZFPlayer_Image(@"ZFPlayer_fast_forward");
|
||||
} else {
|
||||
self.fastImageView.image = ZFPlayer_Image(@"ZFPlayer_fast_backward");
|
||||
}
|
||||
NSString *draggedTime = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
|
||||
NSString *totalTime = [ZFUtilities convertTimeSecond:self.player.totalTime];
|
||||
self.fastTimeLabel.text = [NSString stringWithFormat:@"%@ / %@",draggedTime,totalTime];
|
||||
/// 更新滑杆
|
||||
[self.portraitControlView sliderValueChanged:value currentTimeString:draggedTime];
|
||||
[self.landScapeControlView sliderValueChanged:value currentTimeString:draggedTime];
|
||||
self.bottomPgrogress.isdragging = YES;
|
||||
self.bottomPgrogress.value = value;
|
||||
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideFastView) object:nil];
|
||||
[self performSelector:@selector(hideFastView) withObject:nil afterDelay:0.1];
|
||||
|
||||
if (self.fastViewAnimated) {
|
||||
[UIView animateWithDuration:0.4 animations:^{
|
||||
self.fastView.transform = CGAffineTransformMakeTranslation(forward?8:-8, 0);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
/// 隐藏快进视图
|
||||
- (void)hideFastView {
|
||||
[UIView animateWithDuration:0.4 animations:^{
|
||||
self.fastView.transform = CGAffineTransformIdentity;
|
||||
self.fastView.alpha = 0;
|
||||
} completion:^(BOOL finished) {
|
||||
self.fastView.hidden = YES;
|
||||
}];
|
||||
}
|
||||
|
||||
/// 加载失败
|
||||
- (void)failBtnClick:(UIButton *)sender {
|
||||
[self.player.currentPlayerManager reloadPlayer];
|
||||
}
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (void)setPlayer:(ZFPlayerController *)player {
|
||||
_player = player;
|
||||
self.landScapeControlView.player = player;
|
||||
self.portraitControlView.player = player;
|
||||
/// 解决播放时候黑屏闪一下问题
|
||||
[player.currentPlayerManager.view insertSubview:self.bgImgView atIndex:0];
|
||||
[self.bgImgView addSubview:self.effectView];
|
||||
self.bgImgView.frame = player.currentPlayerManager.view.bounds;
|
||||
self.bgImgView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
self.effectView.frame = self.bgImgView.bounds;
|
||||
}
|
||||
|
||||
- (void)setSeekToPlay:(BOOL)seekToPlay {
|
||||
_seekToPlay = seekToPlay;
|
||||
self.portraitControlView.seekToPlay = seekToPlay;
|
||||
self.landScapeControlView.seekToPlay = seekToPlay;
|
||||
}
|
||||
|
||||
- (void)setEffectViewShow:(BOOL)effectViewShow {
|
||||
_effectViewShow = effectViewShow;
|
||||
if (effectViewShow) {
|
||||
self.bgImgView.hidden = NO;
|
||||
} else {
|
||||
self.bgImgView.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFullScreenMode:(ZFFullScreenMode)fullScreenMode {
|
||||
_fullScreenMode = fullScreenMode;
|
||||
self.portraitControlView.fullScreenMode = fullScreenMode;
|
||||
self.landScapeControlView.fullScreenMode = fullScreenMode;
|
||||
self.player.orientationObserver.fullScreenMode = fullScreenMode;
|
||||
}
|
||||
|
||||
- (void)setShowCustomStatusBar:(BOOL)showCustomStatusBar {
|
||||
_showCustomStatusBar = showCustomStatusBar;
|
||||
self.landScapeControlView.showCustomStatusBar = showCustomStatusBar;
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (UIImageView *)bgImgView {
|
||||
if (!_bgImgView) {
|
||||
_bgImgView = [[UIImageView alloc] init];
|
||||
_bgImgView.userInteractionEnabled = YES;
|
||||
}
|
||||
return _bgImgView;
|
||||
}
|
||||
|
||||
- (UIView *)effectView {
|
||||
if (!_effectView) {
|
||||
if (@available(iOS 8.0, *)) {
|
||||
UIBlurEffect *effect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleDark];
|
||||
_effectView = [[UIVisualEffectView alloc] initWithEffect:effect];
|
||||
} else {
|
||||
UIToolbar *effectView = [[UIToolbar alloc] init];
|
||||
effectView.barStyle = UIBarStyleBlackTranslucent;
|
||||
_effectView = effectView;
|
||||
}
|
||||
}
|
||||
return _effectView;
|
||||
}
|
||||
|
||||
- (ZFPortraitControlView *)portraitControlView {
|
||||
if (!_portraitControlView) {
|
||||
@zf_weakify(self)
|
||||
_portraitControlView = [[ZFPortraitControlView alloc] init];
|
||||
_portraitControlView.sliderValueChanging = ^(CGFloat value, BOOL forward) {
|
||||
@zf_strongify(self)
|
||||
NSString *draggedTime = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
|
||||
/// 更新滑杆和时间
|
||||
[self.landScapeControlView sliderValueChanged:value currentTimeString:draggedTime];
|
||||
self.fastProgressView.value = value;
|
||||
self.bottomPgrogress.isdragging = YES;
|
||||
self.bottomPgrogress.value = value;
|
||||
[self cancelAutoFadeOutControlView];
|
||||
};
|
||||
_portraitControlView.sliderValueChanged = ^(CGFloat value) {
|
||||
@zf_strongify(self)
|
||||
[self.landScapeControlView sliderChangeEnded];
|
||||
self.fastProgressView.value = value;
|
||||
self.bottomPgrogress.isdragging = NO;
|
||||
self.bottomPgrogress.value = value;
|
||||
[self autoFadeOutControlView];
|
||||
};
|
||||
}
|
||||
return _portraitControlView;
|
||||
}
|
||||
|
||||
- (ZFLandScapeControlView *)landScapeControlView {
|
||||
if (!_landScapeControlView) {
|
||||
@zf_weakify(self)
|
||||
_landScapeControlView = [[ZFLandScapeControlView alloc] init];
|
||||
_landScapeControlView.sliderValueChanging = ^(CGFloat value, BOOL forward) {
|
||||
@zf_strongify(self)
|
||||
NSString *draggedTime = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
|
||||
/// 更新滑杆和时间
|
||||
[self.portraitControlView sliderValueChanged:value currentTimeString:draggedTime];
|
||||
self.fastProgressView.value = value;
|
||||
self.bottomPgrogress.isdragging = YES;
|
||||
self.bottomPgrogress.value = value;
|
||||
[self cancelAutoFadeOutControlView];
|
||||
};
|
||||
_landScapeControlView.sliderValueChanged = ^(CGFloat value) {
|
||||
@zf_strongify(self)
|
||||
[self.portraitControlView sliderChangeEnded];
|
||||
self.fastProgressView.value = value;
|
||||
self.bottomPgrogress.isdragging = NO;
|
||||
self.bottomPgrogress.value = value;
|
||||
[self autoFadeOutControlView];
|
||||
};
|
||||
}
|
||||
return _landScapeControlView;
|
||||
}
|
||||
|
||||
- (ZFSpeedLoadingView *)activity {
|
||||
if (!_activity) {
|
||||
_activity = [[ZFSpeedLoadingView alloc] init];
|
||||
}
|
||||
return _activity;
|
||||
}
|
||||
|
||||
- (UIView *)fastView {
|
||||
if (!_fastView) {
|
||||
_fastView = [[UIView alloc] init];
|
||||
_fastView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
|
||||
_fastView.layer.cornerRadius = 4;
|
||||
_fastView.layer.masksToBounds = YES;
|
||||
_fastView.hidden = YES;
|
||||
}
|
||||
return _fastView;
|
||||
}
|
||||
|
||||
- (UIImageView *)fastImageView {
|
||||
if (!_fastImageView) {
|
||||
_fastImageView = [[UIImageView alloc] init];
|
||||
}
|
||||
return _fastImageView;
|
||||
}
|
||||
|
||||
- (UILabel *)fastTimeLabel {
|
||||
if (!_fastTimeLabel) {
|
||||
_fastTimeLabel = [[UILabel alloc] init];
|
||||
_fastTimeLabel.textColor = [UIColor whiteColor];
|
||||
_fastTimeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_fastTimeLabel.font = [UIFont systemFontOfSize:14.0];
|
||||
_fastTimeLabel.adjustsFontSizeToFitWidth = YES;
|
||||
}
|
||||
return _fastTimeLabel;
|
||||
}
|
||||
|
||||
- (ZFSliderView *)fastProgressView {
|
||||
if (!_fastProgressView) {
|
||||
_fastProgressView = [[ZFSliderView alloc] init];
|
||||
_fastProgressView.maximumTrackTintColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.4];
|
||||
_fastProgressView.minimumTrackTintColor = [UIColor whiteColor];
|
||||
_fastProgressView.sliderHeight = 2;
|
||||
_fastProgressView.isHideSliderBlock = NO;
|
||||
}
|
||||
return _fastProgressView;
|
||||
}
|
||||
|
||||
- (UIButton *)failBtn {
|
||||
if (!_failBtn) {
|
||||
_failBtn = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[_failBtn setTitle:@"加载失败,点击重试" forState:UIControlStateNormal];
|
||||
[_failBtn addTarget:self action:@selector(failBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[_failBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
_failBtn.titleLabel.font = [UIFont systemFontOfSize:14.0];
|
||||
_failBtn.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7];
|
||||
_failBtn.hidden = YES;
|
||||
}
|
||||
return _failBtn;
|
||||
}
|
||||
|
||||
- (ZFSliderView *)bottomPgrogress {
|
||||
if (!_bottomPgrogress) {
|
||||
_bottomPgrogress = [[ZFSliderView alloc] init];
|
||||
_bottomPgrogress.maximumTrackTintColor = [UIColor clearColor];
|
||||
_bottomPgrogress.minimumTrackTintColor = [UIColor whiteColor];
|
||||
_bottomPgrogress.bufferTrackTintColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
|
||||
_bottomPgrogress.sliderHeight = 1;
|
||||
_bottomPgrogress.isHideSliderBlock = NO;
|
||||
}
|
||||
return _bottomPgrogress;
|
||||
}
|
||||
|
||||
- (ZFSmallFloatControlView *)floatControlView {
|
||||
if (!_floatControlView) {
|
||||
_floatControlView = [[ZFSmallFloatControlView alloc] init];
|
||||
@zf_weakify(self)
|
||||
_floatControlView.closeClickCallback = ^{
|
||||
@zf_strongify(self)
|
||||
if (self.player.containerType == ZFPlayerContainerTypeCell) {
|
||||
[self.player stopCurrentPlayingCell];
|
||||
} else if (self.player.containerType == ZFPlayerContainerTypeView) {
|
||||
[self.player stopCurrentPlayingView];
|
||||
}
|
||||
[self resetControlView];
|
||||
};
|
||||
}
|
||||
return _floatControlView;
|
||||
}
|
||||
|
||||
- (ZFVolumeBrightnessView *)volumeBrightnessView {
|
||||
if (!_volumeBrightnessView) {
|
||||
_volumeBrightnessView = [[ZFVolumeBrightnessView alloc] init];
|
||||
_volumeBrightnessView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.7];
|
||||
_volumeBrightnessView.hidden = YES;
|
||||
}
|
||||
return _volumeBrightnessView;
|
||||
}
|
||||
|
||||
- (void)setBackBtnClickCallback:(void (^)(void))backBtnClickCallback {
|
||||
_backBtnClickCallback = [backBtnClickCallback copy];
|
||||
self.landScapeControlView.backBtnClickCallback = _backBtnClickCallback;
|
||||
}
|
||||
|
||||
@end
|
||||
42
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayerStatusBar.h
generated
Normal file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// ZFPlayerStatusBar.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ZFPlayerStatusBar : UIView
|
||||
|
||||
/// 刷新时间间隔,默认3秒
|
||||
@property (nonatomic, assign) NSTimeInterval refreshTime;
|
||||
|
||||
- (void)startTimer;
|
||||
|
||||
- (void)destoryTimer;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
392
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPlayerStatusBar.m
generated
Normal file
@@ -0,0 +1,392 @@
|
||||
//
|
||||
// ZFPlayerStatusBar.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFPlayerStatusBar.h"
|
||||
#import <CoreTelephony/CTCarrier.h>
|
||||
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
|
||||
#import "UIView+ZFFrame.h"
|
||||
#import "ZFReachabilityManager.h"
|
||||
#import "ZFUtilities.h"
|
||||
|
||||
@interface ZFPlayerTimerTarget: NSProxy
|
||||
@property (nonatomic, weak) id target;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFPlayerTimerTarget
|
||||
|
||||
+ (instancetype)proxyWithTarget:(id)target {
|
||||
ZFPlayerTimerTarget *proxy = [ZFPlayerTimerTarget alloc];
|
||||
proxy.target = target;
|
||||
return proxy;
|
||||
}
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
|
||||
NSMethodSignature *signature = nil;
|
||||
if ([self.target respondsToSelector:sel]) {
|
||||
signature = [self.target methodSignatureForSelector:sel];
|
||||
} else {
|
||||
/// 动态造一个 void object selector arg 函数签名。
|
||||
/// 目的是返回有效signature,不要因为找不到而crash
|
||||
signature = [NSMethodSignature signatureWithObjCTypes:"v@:@"];
|
||||
}
|
||||
return signature;
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)invocation {
|
||||
if ([self.target respondsToSelector:invocation.selector]) {
|
||||
[invocation invokeWithTarget:self.target];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFPlayerStatusBar()
|
||||
/// 时间
|
||||
@property (nonatomic, strong) UILabel *dateLabel;
|
||||
/// 电池
|
||||
@property (nonatomic, strong) UIView *batteryView;
|
||||
/// 充电标识
|
||||
@property (nonatomic, strong) UIImageView *batteryImageView;
|
||||
/// 充电层
|
||||
@property (nonatomic, strong) CAShapeLayer *batteryLayer;
|
||||
/// 电池边框
|
||||
@property (nonatomic, strong) CAShapeLayer *batteryBoundLayer;
|
||||
/// 电池正极
|
||||
@property (nonatomic, strong) CAShapeLayer *batteryPositiveLayer;
|
||||
/// 电量百分比
|
||||
@property (nonatomic, strong) UILabel *batteryLabel;
|
||||
/// 网络状态
|
||||
@property (nonatomic, strong) UILabel *networkLabel;
|
||||
@property (nonatomic, strong) NSTimer *timer;
|
||||
@property (nonatomic, strong) NSDateFormatter *dateFormatter;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFPlayerStatusBar
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)coder {
|
||||
if (self = [super initWithCoder:coder]) {
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
[self.dateLabel sizeToFit];
|
||||
[self.networkLabel sizeToFit];
|
||||
[self.batteryLabel sizeToFit];
|
||||
|
||||
self.dateLabel.zf_size = CGSizeMake(self.dateLabel.zf_width, 16);
|
||||
self.batteryView.frame = CGRectMake(self.bounds.size.width - 35 - (iPhoneX ? 44 : 0), 0, 22, 10);
|
||||
self.batteryLabel.frame = CGRectMake(self.batteryView.zf_x - 42, 0, self.batteryLabel.zf_width, 16);
|
||||
self.networkLabel.frame = CGRectMake(self.batteryLabel.zf_x - 40, 0, self.networkLabel.zf_width + 13, 14);
|
||||
|
||||
self.dateLabel.center = self.center;
|
||||
self.batteryView.zf_centerY = self.zf_centerY;
|
||||
self.batteryLabel.zf_right = self.batteryView.zf_x - 5;
|
||||
self.batteryLabel.zf_centerY = self.batteryView.zf_centerY;
|
||||
self.networkLabel.zf_right = self.batteryLabel.zf_x - 10;
|
||||
self.networkLabel.zf_centerY = self.batteryView.zf_centerY;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self destoryTimer];
|
||||
}
|
||||
|
||||
- (void)setup {
|
||||
self.refreshTime = 3.0;
|
||||
/// 时间
|
||||
[self addSubview:self.dateLabel];
|
||||
[self addSubview:self.batteryView];
|
||||
/// 电池
|
||||
[self.batteryView.layer addSublayer:self.batteryBoundLayer];
|
||||
/// 正极
|
||||
[self.batteryView.layer addSublayer:self.batteryPositiveLayer];
|
||||
/// 是否在充电
|
||||
[self.batteryView.layer addSublayer:self.batteryLayer];
|
||||
[self.batteryView addSubview:self.batteryImageView];
|
||||
[self addSubview:self.batteryLabel];
|
||||
[self addSubview:self.networkLabel];
|
||||
|
||||
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(batteryLevelDidChangeNotification:)
|
||||
name:UIDeviceBatteryLevelDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(batteryStateDidChangeNotification:)
|
||||
name:UIDeviceBatteryStateDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(localeDidChangeNotification:)
|
||||
name:NSCurrentLocaleDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(networkDidChangeNotification:)
|
||||
name:ZFReachabilityDidChangeNotification
|
||||
object:nil];
|
||||
|
||||
|
||||
}
|
||||
|
||||
- (void)batteryLevelDidChangeNotification:(NSNotification *)noti {
|
||||
[self updateUI];
|
||||
}
|
||||
|
||||
- (void)batteryStateDidChangeNotification:(NSNotification *)noti {
|
||||
[self updateUI];
|
||||
}
|
||||
|
||||
- (void)localeDidChangeNotification:(NSNotification *)noti {
|
||||
[self.dateFormatter setLocale:[NSLocale currentLocale]];
|
||||
[self updateUI];
|
||||
}
|
||||
|
||||
- (void)networkDidChangeNotification:(NSNotification *)noti {
|
||||
self.networkLabel.text = [self networkStatus];
|
||||
[self setNeedsLayout];
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (void)startTimer {
|
||||
self.timer = [NSTimer timerWithTimeInterval:self.refreshTime target:[ZFPlayerTimerTarget proxyWithTarget:self] selector:@selector(updateUI) userInfo:nil repeats:YES];
|
||||
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
|
||||
[self.timer fire];
|
||||
}
|
||||
|
||||
- (void)destoryTimer {
|
||||
if (self.timer) {
|
||||
[self.timer invalidate];
|
||||
self.timer = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - update UI
|
||||
|
||||
- (void)updateUI {
|
||||
[self updateDate];
|
||||
[self updateBattery];
|
||||
[self setNeedsLayout];
|
||||
[self layoutIfNeeded];
|
||||
}
|
||||
|
||||
- (void)updateDate {
|
||||
NSMutableString *dateString = [[NSMutableString alloc] initWithString:[self.dateFormatter stringFromDate:[NSDate date]]];
|
||||
NSRange amRange = [dateString rangeOfString:[self.dateFormatter AMSymbol]];
|
||||
NSRange pmRange = [dateString rangeOfString:[self.dateFormatter PMSymbol]];
|
||||
if (amRange.location != NSNotFound) {
|
||||
[dateString deleteCharactersInRange:amRange];
|
||||
} else if (pmRange.location != NSNotFound) {
|
||||
[dateString deleteCharactersInRange:pmRange];
|
||||
}
|
||||
self.dateLabel.text = dateString;
|
||||
}
|
||||
|
||||
- (void)updateBattery {
|
||||
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
|
||||
CGFloat batteryLevel = [UIDevice currentDevice].batteryLevel;
|
||||
/// -1是模拟器
|
||||
if (batteryLevel < 0) { batteryLevel = 1.0; }
|
||||
CGRect rect = CGRectMake(1.5, 1.5, (20-3)*batteryLevel, 10-3);
|
||||
UIBezierPath *batteryPath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:2];
|
||||
|
||||
UIColor *batteryColor;
|
||||
UIDeviceBatteryState batteryState = [UIDevice currentDevice].batteryState;
|
||||
if (batteryState == UIDeviceBatteryStateCharging || batteryState == UIDeviceBatteryStateFull) { /// 在充电
|
||||
self.batteryImageView.hidden = NO;
|
||||
} else {
|
||||
self.batteryImageView.hidden = YES;
|
||||
}
|
||||
if (@available(iOS 9.0, *)) {
|
||||
if ([NSProcessInfo processInfo].lowPowerModeEnabled) { /// 低电量模式
|
||||
batteryColor = UIColorFromHex(0xF9CF0E);
|
||||
} else {
|
||||
if (batteryState == UIDeviceBatteryStateCharging || batteryState == UIDeviceBatteryStateFull) { /// 在充电
|
||||
batteryColor = UIColorFromHex(0x37CB46);
|
||||
} else if (batteryLevel <= 0.2) { /// 电量低
|
||||
batteryColor = UIColorFromHex(0xF02C2D);
|
||||
} else { /// 电量正常 白色
|
||||
batteryColor = [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (batteryState == UIDeviceBatteryStateCharging || batteryState == UIDeviceBatteryStateFull) { /// 在充电
|
||||
batteryColor = UIColorFromHex(0x37CB46);
|
||||
} else if (batteryLevel <= 0.2) { /// 电量低
|
||||
batteryColor = UIColorFromHex(0xF02C2D);
|
||||
} else { /// 电量正常 白色
|
||||
batteryColor = [UIColor whiteColor];
|
||||
}
|
||||
}
|
||||
|
||||
self.batteryLayer.strokeColor = [UIColor clearColor].CGColor;
|
||||
self.batteryLayer.path = batteryPath.CGPath;
|
||||
self.batteryLayer.fillColor = batteryColor.CGColor;
|
||||
self.batteryLabel.text = [NSString stringWithFormat:@"%.0f%%", batteryLevel*100];
|
||||
}
|
||||
|
||||
- (NSString *)networkStatus {
|
||||
NSString *net = @"WIFI";
|
||||
ZFReachabilityStatus netStatus = [ZFReachabilityManager sharedManager].networkReachabilityStatus;
|
||||
switch (netStatus) {
|
||||
case ZFReachabilityStatusReachableViaWiFi:
|
||||
net = @"WIFI";
|
||||
break;
|
||||
case ZFReachabilityStatusNotReachable:
|
||||
net = @"无网络";
|
||||
break;
|
||||
case ZFReachabilityStatusReachableVia2G:
|
||||
net = @"2G";
|
||||
break;
|
||||
case ZFReachabilityStatusReachableVia3G:
|
||||
net = @"3G";
|
||||
break;
|
||||
case ZFReachabilityStatusReachableVia4G:
|
||||
net = @"4G";
|
||||
break;
|
||||
case ZFReachabilityStatusReachableVia5G:
|
||||
net = @"5G";
|
||||
break;
|
||||
default:
|
||||
net = @"未知";
|
||||
break;
|
||||
}
|
||||
return net;
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (UILabel *)dateLabel {
|
||||
if (!_dateLabel) {
|
||||
_dateLabel = [UILabel new];
|
||||
_dateLabel.bounds = CGRectMake(0, 0, 100, 16);
|
||||
_dateLabel.textColor = [UIColor whiteColor];
|
||||
_dateLabel.font = [UIFont systemFontOfSize:12];
|
||||
_dateLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _dateLabel;
|
||||
}
|
||||
|
||||
- (NSDateFormatter*)dateFormatter {
|
||||
if (!_dateFormatter) {
|
||||
_dateFormatter = [[NSDateFormatter alloc] init];
|
||||
[_dateFormatter setLocale:[NSLocale currentLocale]];
|
||||
[_dateFormatter setDateStyle:NSDateFormatterNoStyle];
|
||||
[_dateFormatter setTimeStyle:NSDateFormatterShortStyle];
|
||||
}
|
||||
return _dateFormatter;
|
||||
}
|
||||
|
||||
- (UIView *)batteryView {
|
||||
if (!_batteryView) {
|
||||
_batteryView = [[UIView alloc] init];
|
||||
}
|
||||
return _batteryView;
|
||||
}
|
||||
|
||||
- (UIImageView *)batteryImageView {
|
||||
if (!_batteryImageView) {
|
||||
_batteryImageView = [[UIImageView alloc] init];
|
||||
_batteryImageView.bounds = CGRectMake(0, 0, 8, 12);
|
||||
_batteryImageView.center = CGPointMake(10, 5);
|
||||
_batteryImageView.image = ZFPlayer_Image(@"ZFPlayer_battery_lightning");
|
||||
}
|
||||
return _batteryImageView;
|
||||
}
|
||||
|
||||
- (CAShapeLayer *)batteryLayer {
|
||||
if (!_batteryLayer) {
|
||||
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
|
||||
CGFloat batteryLevel = [UIDevice currentDevice].batteryLevel;
|
||||
UIBezierPath *batteryPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(1.5, 1.5, (20-3)*batteryLevel, 10-3) cornerRadius:2];
|
||||
_batteryLayer = [CAShapeLayer layer];
|
||||
_batteryLayer.lineWidth = 1;
|
||||
_batteryLayer.strokeColor = [UIColor clearColor].CGColor;
|
||||
_batteryLayer.path = batteryPath.CGPath;
|
||||
_batteryLayer.fillColor = [UIColor whiteColor].CGColor;
|
||||
}
|
||||
return _batteryLayer;
|
||||
}
|
||||
|
||||
- (CAShapeLayer *)batteryBoundLayer {
|
||||
if (!_batteryBoundLayer) {
|
||||
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 20, 10) cornerRadius:2.5];
|
||||
_batteryBoundLayer = [CAShapeLayer layer];
|
||||
_batteryBoundLayer.lineWidth = 1;
|
||||
_batteryBoundLayer.strokeColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8].CGColor;
|
||||
_batteryBoundLayer.path = bezierPath.CGPath;
|
||||
_batteryBoundLayer.fillColor = nil;
|
||||
}
|
||||
return _batteryBoundLayer;
|
||||
}
|
||||
|
||||
- (CAShapeLayer *)batteryPositiveLayer {
|
||||
if (!_batteryPositiveLayer) {
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(22, 3, 1, 3) byRoundingCorners:(UIRectCornerTopRight|UIRectCornerBottomRight) cornerRadii:CGSizeMake(2, 2)];
|
||||
_batteryPositiveLayer = [CAShapeLayer layer];
|
||||
_batteryPositiveLayer.lineWidth = 0.5;
|
||||
_batteryPositiveLayer.strokeColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8].CGColor;
|
||||
_batteryPositiveLayer.path = path.CGPath;
|
||||
_batteryPositiveLayer.fillColor = [[UIColor whiteColor] colorWithAlphaComponent:0.8].CGColor;
|
||||
}
|
||||
return _batteryPositiveLayer;
|
||||
}
|
||||
|
||||
- (UILabel *)batteryLabel {
|
||||
if (!_batteryLabel) {
|
||||
_batteryLabel = [[UILabel alloc] init];
|
||||
_batteryLabel.textColor = [UIColor whiteColor];
|
||||
_batteryLabel.font = [UIFont systemFontOfSize:11];
|
||||
_batteryLabel.textAlignment = NSTextAlignmentRight;
|
||||
}
|
||||
return _batteryLabel;
|
||||
}
|
||||
|
||||
- (UILabel *)networkLabel {
|
||||
if (!_networkLabel) {
|
||||
_networkLabel = [[UILabel alloc] init];
|
||||
_networkLabel.layer.cornerRadius = 7;
|
||||
_networkLabel.layer.borderWidth = 1;
|
||||
_networkLabel.layer.borderColor = [UIColor lightGrayColor].CGColor;
|
||||
_networkLabel.textColor = [UIColor whiteColor];
|
||||
_networkLabel.font = [UIFont systemFontOfSize:9];
|
||||
_networkLabel.textAlignment = NSTextAlignmentCenter;
|
||||
_networkLabel.text = @"WIFI";
|
||||
}
|
||||
return _networkLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
111
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPortraitControlView.h
generated
Executable file
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// ZFPortraitControlView.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ZFSliderView.h"
|
||||
#if __has_include(<ZFPlayer/ZFPlayerController.h>)
|
||||
#import <ZFPlayer/ZFPlayerController.h>
|
||||
#else
|
||||
#import "ZFPlayerController.h"
|
||||
#endif
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ZFPortraitControlView : UIView
|
||||
|
||||
/// 底部工具栏
|
||||
@property (nonatomic, strong, readonly) UIView *bottomToolView;
|
||||
|
||||
/// 顶部工具栏
|
||||
@property (nonatomic, strong, readonly) UIView *topToolView;
|
||||
|
||||
/// 标题
|
||||
@property (nonatomic, strong, readonly) UILabel *titleLabel;
|
||||
|
||||
/// 播放或暂停按钮
|
||||
@property (nonatomic, strong, readonly) UIButton *playOrPauseBtn;
|
||||
|
||||
/// 播放的当前时间
|
||||
@property (nonatomic, strong, readonly) UILabel *currentTimeLabel;
|
||||
|
||||
/// 滑杆
|
||||
@property (nonatomic, strong, readonly) ZFSliderView *slider;
|
||||
|
||||
/// 视频总时间
|
||||
@property (nonatomic, strong, readonly) UILabel *totalTimeLabel;
|
||||
|
||||
/// 全屏按钮
|
||||
@property (nonatomic, strong, readonly) UIButton *fullScreenBtn;
|
||||
|
||||
/// 播放器
|
||||
@property (nonatomic, weak) ZFPlayerController *player;
|
||||
|
||||
/// slider滑动中
|
||||
@property (nonatomic, copy, nullable) void(^sliderValueChanging)(CGFloat value,BOOL forward);
|
||||
|
||||
/// slider滑动结束
|
||||
@property (nonatomic, copy, nullable) void(^sliderValueChanged)(CGFloat value);
|
||||
|
||||
/// 如果是暂停状态,seek完是否播放,默认YES
|
||||
@property (nonatomic, assign) BOOL seekToPlay;
|
||||
|
||||
/// 全屏模式
|
||||
@property (nonatomic, assign) ZFFullScreenMode fullScreenMode;
|
||||
|
||||
/// 重置控制层
|
||||
- (void)resetControlView;
|
||||
|
||||
/// 显示控制层
|
||||
- (void)showControlView;
|
||||
|
||||
/// 隐藏控制层
|
||||
- (void)hideControlView;
|
||||
|
||||
/// 设置播放时间
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime;
|
||||
|
||||
/// 设置缓冲时间
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime;
|
||||
|
||||
/// 是否响应该手势
|
||||
- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch;
|
||||
|
||||
/// 标题和全屏模式
|
||||
- (void)showTitle:(NSString *_Nullable)title fullScreenMode:(ZFFullScreenMode)fullScreenMode;
|
||||
|
||||
/// 根据当前播放状态取反
|
||||
- (void)playOrPause;
|
||||
|
||||
/// 播放按钮状态
|
||||
- (void)playBtnSelectedState:(BOOL)selected;
|
||||
|
||||
/// 调节播放进度slider和当前时间更新
|
||||
- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString;
|
||||
|
||||
/// 滑杆结束滑动
|
||||
- (void)sliderChangeEnded;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
387
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFPortraitControlView.m
generated
Executable file
@@ -0,0 +1,387 @@
|
||||
//
|
||||
// ZFPortraitControlView.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFPortraitControlView.h"
|
||||
#import "UIView+ZFFrame.h"
|
||||
#import "ZFUtilities.h"
|
||||
#if __has_include(<ZFPlayer/ZFPlayer.h>)
|
||||
#import <ZFPlayer/ZFPlayerConst.h>
|
||||
#else
|
||||
#import "ZFPlayerConst.h"
|
||||
#endif
|
||||
|
||||
@interface ZFPortraitControlView () <ZFSliderViewDelegate>
|
||||
/// 底部工具栏
|
||||
@property (nonatomic, strong) UIView *bottomToolView;
|
||||
/// 顶部工具栏
|
||||
@property (nonatomic, strong) UIView *topToolView;
|
||||
/// 标题
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
/// 播放或暂停按钮
|
||||
@property (nonatomic, strong) UIButton *playOrPauseBtn;
|
||||
/// 播放的当前时间
|
||||
@property (nonatomic, strong) UILabel *currentTimeLabel;
|
||||
/// 滑杆
|
||||
@property (nonatomic, strong) ZFSliderView *slider;
|
||||
/// 视频总时间
|
||||
@property (nonatomic, strong) UILabel *totalTimeLabel;
|
||||
/// 全屏按钮
|
||||
@property (nonatomic, strong) UIButton *fullScreenBtn;
|
||||
|
||||
@property (nonatomic, assign) BOOL isShow;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFPortraitControlView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
// 添加子控件
|
||||
[self addSubview:self.topToolView];
|
||||
[self addSubview:self.bottomToolView];
|
||||
[self addSubview:self.playOrPauseBtn];
|
||||
[self.topToolView addSubview:self.titleLabel];
|
||||
[self.bottomToolView addSubview:self.currentTimeLabel];
|
||||
[self.bottomToolView addSubview:self.slider];
|
||||
[self.bottomToolView addSubview:self.totalTimeLabel];
|
||||
[self.bottomToolView addSubview:self.fullScreenBtn];
|
||||
|
||||
// 设置子控件的响应事件
|
||||
[self makeSubViewsAction];
|
||||
|
||||
[self resetControlView];
|
||||
self.clipsToBounds = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
|
||||
CGFloat min_x = 0;
|
||||
CGFloat min_y = 0;
|
||||
CGFloat min_w = 0;
|
||||
CGFloat min_h = 0;
|
||||
CGFloat min_view_w = self.bounds.size.width;
|
||||
CGFloat min_view_h = self.bounds.size.height;
|
||||
CGFloat min_margin = 9;
|
||||
|
||||
min_x = 0;
|
||||
min_y = 0;
|
||||
min_w = min_view_w;
|
||||
min_h = 40;
|
||||
self.topToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = 15;
|
||||
min_y = 5;
|
||||
min_w = min_view_w - min_x - 15;
|
||||
min_h = 30;
|
||||
self.titleLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_h = 40;
|
||||
min_x = 0;
|
||||
min_y = min_view_h - min_h;
|
||||
min_w = min_view_w;
|
||||
self.bottomToolView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = 0;
|
||||
min_y = 0;
|
||||
min_w = 44;
|
||||
min_h = min_w;
|
||||
self.playOrPauseBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.playOrPauseBtn.center = self.center;
|
||||
|
||||
min_x = min_margin;
|
||||
min_w = 62;
|
||||
min_h = 28;
|
||||
min_y = (self.bottomToolView.zf_height - min_h)/2;
|
||||
self.currentTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_w = 28;
|
||||
min_h = min_w;
|
||||
min_x = self.bottomToolView.zf_width - min_w - min_margin;
|
||||
min_y = 0;
|
||||
self.fullScreenBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.fullScreenBtn.zf_centerY = self.currentTimeLabel.zf_centerY;
|
||||
|
||||
min_w = 62;
|
||||
min_h = 28;
|
||||
min_x = self.fullScreenBtn.zf_left - min_w - 4;
|
||||
min_y = 0;
|
||||
self.totalTimeLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.totalTimeLabel.zf_centerY = self.currentTimeLabel.zf_centerY;
|
||||
|
||||
min_x = self.currentTimeLabel.zf_right + 4;
|
||||
min_y = 0;
|
||||
min_w = self.totalTimeLabel.zf_left - min_x - 4;
|
||||
min_h = 30;
|
||||
self.slider.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.slider.zf_centerY = self.currentTimeLabel.zf_centerY;
|
||||
|
||||
if (!self.isShow) {
|
||||
self.topToolView.zf_y = -self.topToolView.zf_height;
|
||||
self.bottomToolView.zf_y = self.zf_height;
|
||||
self.playOrPauseBtn.alpha = 0;
|
||||
} else {
|
||||
self.topToolView.zf_y = 0;
|
||||
self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
|
||||
self.playOrPauseBtn.alpha = 1;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)makeSubViewsAction {
|
||||
[self.playOrPauseBtn addTarget:self action:@selector(playPauseButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self.fullScreenBtn addTarget:self action:@selector(fullScreenButtonClickAction:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
|
||||
#pragma mark - action
|
||||
|
||||
- (void)playPauseButtonClickAction:(UIButton *)sender {
|
||||
[self playOrPause];
|
||||
}
|
||||
|
||||
- (void)fullScreenButtonClickAction:(UIButton *)sender {
|
||||
[self.player enterFullScreen:YES animated:YES];
|
||||
}
|
||||
|
||||
/// 根据当前播放状态取反
|
||||
- (void)playOrPause {
|
||||
self.playOrPauseBtn.selected = !self.playOrPauseBtn.isSelected;
|
||||
self.playOrPauseBtn.isSelected? [self.player.currentPlayerManager play]: [self.player.currentPlayerManager pause];
|
||||
}
|
||||
|
||||
- (void)playBtnSelectedState:(BOOL)selected {
|
||||
self.playOrPauseBtn.selected = selected;
|
||||
}
|
||||
|
||||
#pragma mark - ZFSliderViewDelegate
|
||||
|
||||
- (void)sliderTouchBegan:(float)value {
|
||||
self.slider.isdragging = YES;
|
||||
}
|
||||
|
||||
- (void)sliderTouchEnded:(float)value {
|
||||
if (self.player.totalTime > 0) {
|
||||
self.slider.isdragging = YES;
|
||||
if (self.sliderValueChanging) self.sliderValueChanging(value, self.slider.isForward);
|
||||
@zf_weakify(self)
|
||||
[self.player seekToTime:self.player.totalTime*value completionHandler:^(BOOL finished) {
|
||||
@zf_strongify(self)
|
||||
self.slider.isdragging = NO;
|
||||
if (finished) {
|
||||
if (self.sliderValueChanged) self.sliderValueChanged(value);
|
||||
}
|
||||
}];
|
||||
if (self.seekToPlay) {
|
||||
[self.player.currentPlayerManager play];
|
||||
}
|
||||
} else {
|
||||
self.slider.isdragging = NO;
|
||||
self.slider.value = 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sliderValueChanged:(float)value {
|
||||
if (self.player.totalTime == 0) {
|
||||
self.slider.value = 0;
|
||||
return;
|
||||
}
|
||||
self.slider.isdragging = YES;
|
||||
NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
|
||||
self.currentTimeLabel.text = currentTimeString;
|
||||
if (self.sliderValueChanging) self.sliderValueChanging(value,self.slider.isForward);
|
||||
}
|
||||
|
||||
- (void)sliderTapped:(float)value {
|
||||
[self sliderTouchEnded:value];
|
||||
NSString *currentTimeString = [ZFUtilities convertTimeSecond:self.player.totalTime*value];
|
||||
self.currentTimeLabel.text = currentTimeString;
|
||||
}
|
||||
|
||||
#pragma mark - public method
|
||||
|
||||
/** 重置ControlView */
|
||||
- (void)resetControlView {
|
||||
self.bottomToolView.alpha = 1;
|
||||
self.slider.value = 0;
|
||||
self.slider.bufferValue = 0;
|
||||
self.currentTimeLabel.text = @"00:00";
|
||||
self.totalTimeLabel.text = @"00:00";
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.playOrPauseBtn.selected = YES;
|
||||
self.titleLabel.text = @"";
|
||||
}
|
||||
|
||||
- (void)showControlView {
|
||||
self.topToolView.alpha = 1;
|
||||
self.bottomToolView.alpha = 1;
|
||||
self.isShow = YES;
|
||||
self.topToolView.zf_y = 0;
|
||||
self.bottomToolView.zf_y = self.zf_height - self.bottomToolView.zf_height;
|
||||
self.playOrPauseBtn.alpha = 1;
|
||||
self.player.statusBarHidden = NO;
|
||||
}
|
||||
|
||||
- (void)hideControlView {
|
||||
self.isShow = NO;
|
||||
self.topToolView.zf_y = -self.topToolView.zf_height;
|
||||
self.bottomToolView.zf_y = self.zf_height;
|
||||
self.player.statusBarHidden = NO;
|
||||
self.playOrPauseBtn.alpha = 0;
|
||||
self.topToolView.alpha = 0;
|
||||
self.bottomToolView.alpha = 0;
|
||||
}
|
||||
|
||||
- (BOOL)shouldResponseGestureWithPoint:(CGPoint)point withGestureType:(ZFPlayerGestureType)type touch:(nonnull UITouch *)touch {
|
||||
CGRect sliderRect = [self.bottomToolView convertRect:self.slider.frame toView:self];
|
||||
if (CGRectContainsPoint(sliderRect, point)) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer currentTime:(NSTimeInterval)currentTime totalTime:(NSTimeInterval)totalTime {
|
||||
if (!self.slider.isdragging) {
|
||||
NSString *currentTimeString = [ZFUtilities convertTimeSecond:currentTime];
|
||||
self.currentTimeLabel.text = currentTimeString;
|
||||
NSString *totalTimeString = [ZFUtilities convertTimeSecond:totalTime];
|
||||
self.totalTimeLabel.text = totalTimeString;
|
||||
self.slider.value = videoPlayer.progress;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)videoPlayer:(ZFPlayerController *)videoPlayer bufferTime:(NSTimeInterval)bufferTime {
|
||||
self.slider.bufferValue = videoPlayer.bufferProgress;
|
||||
}
|
||||
|
||||
- (void)showTitle:(NSString *)title fullScreenMode:(ZFFullScreenMode)fullScreenMode {
|
||||
self.titleLabel.text = title;
|
||||
self.player.orientationObserver.fullScreenMode = fullScreenMode;
|
||||
}
|
||||
|
||||
/// 调节播放进度slider和当前时间更新
|
||||
- (void)sliderValueChanged:(CGFloat)value currentTimeString:(NSString *)timeString {
|
||||
self.slider.value = value;
|
||||
self.currentTimeLabel.text = timeString;
|
||||
self.slider.isdragging = YES;
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.slider.sliderBtn.transform = CGAffineTransformMakeScale(1.2, 1.2);
|
||||
}];
|
||||
}
|
||||
|
||||
/// 滑杆结束滑动
|
||||
- (void)sliderChangeEnded {
|
||||
self.slider.isdragging = NO;
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
self.slider.sliderBtn.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (void)setFullScreenMode:(ZFFullScreenMode)fullScreenMode {
|
||||
_fullScreenMode = fullScreenMode;
|
||||
self.player.orientationObserver.fullScreenMode = fullScreenMode;
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (UIView *)topToolView {
|
||||
if (!_topToolView) {
|
||||
_topToolView = [[UIView alloc] init];
|
||||
UIImage *image = ZFPlayer_Image(@"ZFPlayer_top_shadow");
|
||||
_topToolView.layer.contents = (id)image.CGImage;
|
||||
}
|
||||
return _topToolView;
|
||||
}
|
||||
|
||||
- (UILabel *)titleLabel {
|
||||
if (!_titleLabel) {
|
||||
_titleLabel = [[UILabel alloc] init];
|
||||
_titleLabel.textColor = [UIColor whiteColor];
|
||||
_titleLabel.font = [UIFont systemFontOfSize:15.0];
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
|
||||
- (UIView *)bottomToolView {
|
||||
if (!_bottomToolView) {
|
||||
_bottomToolView = [[UIView alloc] init];
|
||||
UIImage *image = ZFPlayer_Image(@"ZFPlayer_bottom_shadow");
|
||||
_bottomToolView.layer.contents = (id)image.CGImage;
|
||||
}
|
||||
return _bottomToolView;
|
||||
}
|
||||
|
||||
- (UIButton *)playOrPauseBtn {
|
||||
if (!_playOrPauseBtn) {
|
||||
_playOrPauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_playOrPauseBtn setImage:ZFPlayer_Image(@"new_allPlay_44x44_") forState:UIControlStateNormal];
|
||||
[_playOrPauseBtn setImage:ZFPlayer_Image(@"new_allPause_44x44_") forState:UIControlStateSelected];
|
||||
}
|
||||
return _playOrPauseBtn;
|
||||
}
|
||||
|
||||
- (UILabel *)currentTimeLabel {
|
||||
if (!_currentTimeLabel) {
|
||||
_currentTimeLabel = [[UILabel alloc] init];
|
||||
_currentTimeLabel.textColor = [UIColor whiteColor];
|
||||
_currentTimeLabel.font = [UIFont systemFontOfSize:14.0f];
|
||||
_currentTimeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _currentTimeLabel;
|
||||
}
|
||||
|
||||
- (ZFSliderView *)slider {
|
||||
if (!_slider) {
|
||||
_slider = [[ZFSliderView alloc] init];
|
||||
_slider.delegate = self;
|
||||
_slider.maximumTrackTintColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.8];
|
||||
_slider.bufferTrackTintColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
|
||||
_slider.minimumTrackTintColor = [UIColor whiteColor];
|
||||
[_slider setThumbImage:ZFPlayer_Image(@"ZFPlayer_slider") forState:UIControlStateNormal];
|
||||
_slider.sliderHeight = 2;
|
||||
}
|
||||
return _slider;
|
||||
}
|
||||
|
||||
- (UILabel *)totalTimeLabel {
|
||||
if (!_totalTimeLabel) {
|
||||
_totalTimeLabel = [[UILabel alloc] init];
|
||||
_totalTimeLabel.textColor = [UIColor whiteColor];
|
||||
_totalTimeLabel.font = [UIFont systemFontOfSize:14.0f];
|
||||
_totalTimeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _totalTimeLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)fullScreenBtn {
|
||||
if (!_fullScreenBtn) {
|
||||
_fullScreenBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_fullScreenBtn setImage:ZFPlayer_Image(@"ZFPlayer_fullscreen") forState:UIControlStateNormal];
|
||||
}
|
||||
return _fullScreenBtn;
|
||||
}
|
||||
|
||||
@end
|
||||
118
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSliderView.h
generated
Normal file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// ZFSliderView.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@protocol ZFSliderViewDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
// 滑块滑动开始
|
||||
- (void)sliderTouchBegan:(float)value;
|
||||
// 滑块滑动中
|
||||
- (void)sliderValueChanged:(float)value;
|
||||
// 滑块滑动结束
|
||||
- (void)sliderTouchEnded:(float)value;
|
||||
// 滑杆点击
|
||||
- (void)sliderTapped:(float)value;
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFSliderButton : UIButton
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFSliderView : UIView
|
||||
|
||||
@property (nonatomic, weak) id<ZFSliderViewDelegate> delegate;
|
||||
|
||||
/** 滑块 */
|
||||
@property (nonatomic, strong, readonly) ZFSliderButton *sliderBtn;
|
||||
|
||||
/** 默认滑杆的颜色 */
|
||||
@property (nonatomic, strong) UIColor *maximumTrackTintColor;
|
||||
|
||||
/** 滑杆进度颜色 */
|
||||
@property (nonatomic, strong) UIColor *minimumTrackTintColor;
|
||||
|
||||
/** 缓存进度颜色 */
|
||||
@property (nonatomic, strong) UIColor *bufferTrackTintColor;
|
||||
|
||||
/** loading进度颜色 */
|
||||
@property (nonatomic, strong) UIColor *loadingTintColor;
|
||||
|
||||
/** 默认滑杆的图片 */
|
||||
@property (nonatomic, strong) UIImage *maximumTrackImage;
|
||||
|
||||
/** 滑杆进度的图片 */
|
||||
@property (nonatomic, strong) UIImage *minimumTrackImage;
|
||||
|
||||
/** 缓存进度的图片 */
|
||||
@property (nonatomic, strong) UIImage *bufferTrackImage;
|
||||
|
||||
/** 滑杆进度 */
|
||||
@property (nonatomic, assign) float value;
|
||||
|
||||
/** 缓存进度 */
|
||||
@property (nonatomic, assign) float bufferValue;
|
||||
|
||||
/** 是否允许点击,默认是YES */
|
||||
@property (nonatomic, assign) BOOL allowTapped;
|
||||
|
||||
/** 是否允许点击,默认是YES */
|
||||
@property (nonatomic, assign) BOOL animate;
|
||||
|
||||
/** 设置滑杆的高度 */
|
||||
@property (nonatomic, assign) CGFloat sliderHeight;
|
||||
|
||||
/** 设置滑杆的圆角 */
|
||||
@property (nonatomic, assign) CGFloat sliderRadius;
|
||||
|
||||
/** 是否隐藏滑块(默认为NO) */
|
||||
@property (nonatomic, assign) BOOL isHideSliderBlock;
|
||||
|
||||
/// 是否正在拖动
|
||||
@property (nonatomic, assign) BOOL isdragging;
|
||||
|
||||
/// 向前还是向后拖动
|
||||
@property (nonatomic, assign) BOOL isForward;
|
||||
|
||||
@property (nonatomic, assign) CGSize thumbSize;
|
||||
|
||||
/**
|
||||
* Starts animation of the spinner.
|
||||
*/
|
||||
- (void)startAnimating;
|
||||
|
||||
/**
|
||||
* Stops animation of the spinnner.
|
||||
*/
|
||||
- (void)stopAnimating;
|
||||
|
||||
// 设置滑块背景色
|
||||
- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state;
|
||||
|
||||
// 设置滑块图片
|
||||
- (void)setThumbImage:(UIImage *)image forState:(UIControlState)state;
|
||||
|
||||
@end
|
||||
426
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSliderView.m
generated
Normal file
@@ -0,0 +1,426 @@
|
||||
//
|
||||
// ZFSliderView.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFSliderView.h"
|
||||
#import "UIView+ZFFrame.h"
|
||||
|
||||
/** 滑块的大小 */
|
||||
static const CGFloat kSliderBtnWH = 19.0;
|
||||
/** 进度的高度 */
|
||||
static const CGFloat kProgressH = 1.0;
|
||||
/** 拖动slider动画的时间*/
|
||||
static const CGFloat kAnimate = 0.3;
|
||||
|
||||
@implementation ZFSliderButton
|
||||
|
||||
// 重写此方法将按钮的点击范围扩大
|
||||
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
|
||||
CGRect bounds = self.bounds;
|
||||
// 扩大点击区域
|
||||
bounds = CGRectInset(bounds, -20, -20);
|
||||
// 若点击的点在新的bounds里面。就返回yes
|
||||
return CGRectContainsPoint(bounds, point);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFSliderView ()
|
||||
|
||||
/** 进度背景 */
|
||||
@property (nonatomic, strong) UIImageView *bgProgressView;
|
||||
/** 缓存进度 */
|
||||
@property (nonatomic, strong) UIImageView *bufferProgressView;
|
||||
/** 滑动进度 */
|
||||
@property (nonatomic, strong) UIImageView *sliderProgressView;
|
||||
/** 滑块 */
|
||||
@property (nonatomic, strong) ZFSliderButton *sliderBtn;
|
||||
|
||||
@property (nonatomic, strong) UIView *loadingBarView;
|
||||
|
||||
@property (nonatomic, assign) BOOL isLoading;
|
||||
|
||||
@property (nonatomic, strong) UITapGestureRecognizer *tapGesture;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFSliderView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.allowTapped = YES;
|
||||
self.animate = YES;
|
||||
[self addSubViews];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
self.allowTapped = YES;
|
||||
self.animate = YES;
|
||||
[self addSubViews];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
if (isnan(self.value) || isnan(self.bufferValue)) return;
|
||||
|
||||
CGFloat min_x = 0;
|
||||
CGFloat min_y = 0;
|
||||
CGFloat min_w = 0;
|
||||
CGFloat min_h = 0;
|
||||
CGFloat min_view_w = self.bounds.size.width;
|
||||
CGFloat min_view_h = self.bounds.size.height;
|
||||
|
||||
min_x = 0;
|
||||
min_w = min_view_w;
|
||||
min_y = 0;
|
||||
min_h = self.sliderHeight;
|
||||
self.bgProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = 0;
|
||||
min_y = 0;
|
||||
min_w = self.thumbSize.width;
|
||||
min_h = self.thumbSize.height;
|
||||
self.sliderBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
self.sliderBtn.zf_centerX = self.bgProgressView.zf_width * self.value;
|
||||
|
||||
min_x = 0;
|
||||
min_y = 0;
|
||||
if (self.sliderBtn.hidden) {
|
||||
min_w = self.bgProgressView.zf_width * self.value;
|
||||
} else {
|
||||
min_w = self.sliderBtn.zf_centerX;
|
||||
}
|
||||
min_h = self.sliderHeight;
|
||||
self.sliderProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = 0;
|
||||
min_y = 0;
|
||||
min_w = self.bgProgressView.zf_width * self.bufferValue;
|
||||
min_h = self.sliderHeight;
|
||||
self.bufferProgressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_w = 0.1;
|
||||
min_h = self.sliderHeight;
|
||||
min_x = (min_view_w - min_w)/2;
|
||||
min_y = (min_view_h - min_h)/2;
|
||||
self.loadingBarView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
self.bgProgressView.zf_centerY = min_view_h * 0.5;
|
||||
self.bufferProgressView.zf_centerY = min_view_h * 0.5;
|
||||
self.sliderProgressView.zf_centerY = min_view_h * 0.5;
|
||||
self.sliderBtn.zf_centerY = min_view_h * 0.5;
|
||||
}
|
||||
|
||||
/**
|
||||
添加子视图
|
||||
*/
|
||||
- (void)addSubViews {
|
||||
self.thumbSize = CGSizeMake(kSliderBtnWH, kSliderBtnWH);
|
||||
self.sliderHeight = kProgressH;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
[self addSubview:self.bgProgressView];
|
||||
[self addSubview:self.bufferProgressView];
|
||||
[self addSubview:self.sliderProgressView];
|
||||
[self addSubview:self.sliderBtn];
|
||||
[self addSubview:self.loadingBarView];
|
||||
|
||||
// 添加点击手势
|
||||
self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)];
|
||||
[self addGestureRecognizer:self.tapGesture];
|
||||
|
||||
// 添加滑动手势
|
||||
UIPanGestureRecognizer *sliderGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(sliderGesture:)];
|
||||
[self addGestureRecognizer:sliderGesture];
|
||||
}
|
||||
|
||||
#pragma mark - Setter
|
||||
|
||||
- (void)setMaximumTrackTintColor:(UIColor *)maximumTrackTintColor {
|
||||
_maximumTrackTintColor = maximumTrackTintColor;
|
||||
self.bgProgressView.backgroundColor = maximumTrackTintColor;
|
||||
}
|
||||
|
||||
- (void)setMinimumTrackTintColor:(UIColor *)minimumTrackTintColor {
|
||||
_minimumTrackTintColor = minimumTrackTintColor;
|
||||
self.sliderProgressView.backgroundColor = minimumTrackTintColor;
|
||||
}
|
||||
|
||||
- (void)setBufferTrackTintColor:(UIColor *)bufferTrackTintColor {
|
||||
_bufferTrackTintColor = bufferTrackTintColor;
|
||||
self.bufferProgressView.backgroundColor = bufferTrackTintColor;
|
||||
}
|
||||
|
||||
- (void)setLoadingTintColor:(UIColor *)loadingTintColor {
|
||||
_loadingTintColor = loadingTintColor;
|
||||
self.loadingBarView.backgroundColor = loadingTintColor;
|
||||
}
|
||||
|
||||
- (void)setMaximumTrackImage:(UIImage *)maximumTrackImage {
|
||||
_maximumTrackImage = maximumTrackImage;
|
||||
self.bgProgressView.image = maximumTrackImage;
|
||||
self.maximumTrackTintColor = [UIColor clearColor];
|
||||
}
|
||||
|
||||
- (void)setMinimumTrackImage:(UIImage *)minimumTrackImage {
|
||||
_minimumTrackImage = minimumTrackImage;
|
||||
self.sliderProgressView.image = minimumTrackImage;
|
||||
self.minimumTrackTintColor = [UIColor clearColor];
|
||||
}
|
||||
|
||||
- (void)setBufferTrackImage:(UIImage *)bufferTrackImage {
|
||||
_bufferTrackImage = bufferTrackImage;
|
||||
self.bufferProgressView.image = bufferTrackImage;
|
||||
self.bufferTrackTintColor = [UIColor clearColor];
|
||||
}
|
||||
|
||||
- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state {
|
||||
[self.sliderBtn setBackgroundImage:image forState:state];
|
||||
}
|
||||
|
||||
- (void)setThumbImage:(UIImage *)image forState:(UIControlState)state {
|
||||
[self.sliderBtn setImage:image forState:state];
|
||||
}
|
||||
|
||||
- (void)setValue:(float)value {
|
||||
if (isnan(value)) return;
|
||||
value = MIN(1.0, value);
|
||||
_value = value;
|
||||
if (self.sliderBtn.hidden) {
|
||||
self.sliderProgressView.zf_width = self.bgProgressView.zf_width * value;
|
||||
} else {
|
||||
self.sliderBtn.zf_centerX = self.bgProgressView.zf_width * value;
|
||||
self.sliderProgressView.zf_width = self.sliderBtn.zf_centerX;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setBufferValue:(float)bufferValue {
|
||||
if (isnan(bufferValue)) return;
|
||||
bufferValue = MIN(1.0, bufferValue);
|
||||
_bufferValue = bufferValue;
|
||||
self.bufferProgressView.zf_width = self.bgProgressView.zf_width * bufferValue;
|
||||
}
|
||||
|
||||
- (void)setAllowTapped:(BOOL)allowTapped {
|
||||
_allowTapped = allowTapped;
|
||||
if (!allowTapped) {
|
||||
[self removeGestureRecognizer:self.tapGesture];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setSliderHeight:(CGFloat)sliderHeight {
|
||||
if (isnan(sliderHeight)) return;
|
||||
_sliderHeight = sliderHeight;
|
||||
self.bgProgressView.zf_height = sliderHeight;
|
||||
self.bufferProgressView.zf_height = sliderHeight;
|
||||
self.sliderProgressView.zf_height = sliderHeight;
|
||||
}
|
||||
|
||||
- (void)setSliderRadius:(CGFloat)sliderRadius {
|
||||
if (isnan(sliderRadius)) return;
|
||||
_sliderRadius = sliderRadius;
|
||||
self.bgProgressView.layer.cornerRadius = sliderRadius;
|
||||
self.bufferProgressView.layer.cornerRadius = sliderRadius;
|
||||
self.sliderProgressView.layer.cornerRadius = sliderRadius;
|
||||
self.bgProgressView.layer.masksToBounds = YES;
|
||||
self.bufferProgressView.layer.masksToBounds = YES;
|
||||
self.sliderProgressView.layer.masksToBounds = YES;
|
||||
}
|
||||
|
||||
- (void)setIsHideSliderBlock:(BOOL)isHideSliderBlock {
|
||||
_isHideSliderBlock = isHideSliderBlock;
|
||||
// 隐藏滑块,滑杆不可点击
|
||||
if (isHideSliderBlock) {
|
||||
self.sliderBtn.hidden = YES;
|
||||
self.bgProgressView.zf_left = 0;
|
||||
self.bufferProgressView.zf_left = 0;
|
||||
self.sliderProgressView.zf_left = 0;
|
||||
self.allowTapped = NO;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts animation of the spinner.
|
||||
*/
|
||||
- (void)startAnimating {
|
||||
if (self.isLoading) return;
|
||||
self.isLoading = YES;
|
||||
self.bufferProgressView.hidden = YES;
|
||||
self.sliderProgressView.hidden = YES;
|
||||
self.sliderBtn.hidden = YES;
|
||||
self.loadingBarView.hidden = NO;
|
||||
|
||||
[self.loadingBarView.layer removeAllAnimations];
|
||||
CAAnimationGroup *animationGroup = [[CAAnimationGroup alloc] init];
|
||||
animationGroup.duration = 0.4;
|
||||
animationGroup.beginTime = CACurrentMediaTime() + 0.4;
|
||||
animationGroup.repeatCount = MAXFLOAT;
|
||||
animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
|
||||
|
||||
CABasicAnimation *scaleAnimation = [CABasicAnimation animation];
|
||||
scaleAnimation.keyPath = @"transform.scale.x";
|
||||
scaleAnimation.fromValue = @(1000.0f);
|
||||
scaleAnimation.toValue = @(self.zf_width * 10);
|
||||
|
||||
CABasicAnimation *alphaAnimation = [CABasicAnimation animation];
|
||||
alphaAnimation.keyPath = @"opacity";
|
||||
alphaAnimation.fromValue = @(1.0f);
|
||||
alphaAnimation.toValue = @(0.0f);
|
||||
|
||||
[animationGroup setAnimations:@[scaleAnimation, alphaAnimation]];
|
||||
[self.loadingBarView.layer addAnimation:animationGroup forKey:@"loading"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops animation of the spinnner.
|
||||
*/
|
||||
- (void)stopAnimating {
|
||||
self.isLoading = NO;
|
||||
self.bufferProgressView.hidden = NO;
|
||||
self.sliderProgressView.hidden = NO;
|
||||
self.sliderBtn.hidden = self.isHideSliderBlock;
|
||||
self.loadingBarView.hidden = YES;
|
||||
[self.loadingBarView.layer removeAllAnimations];
|
||||
}
|
||||
|
||||
#pragma mark - User Action
|
||||
|
||||
- (void)sliderGesture:(UIGestureRecognizer *)gesture {
|
||||
switch (gesture.state) {
|
||||
case UIGestureRecognizerStateBegan: {
|
||||
[self sliderBtnTouchBegin:self.sliderBtn];
|
||||
}
|
||||
break;
|
||||
case UIGestureRecognizerStateChanged: {
|
||||
[self sliderBtnDragMoving:self.sliderBtn point:[gesture locationInView:self.bgProgressView]];
|
||||
}
|
||||
break;
|
||||
case UIGestureRecognizerStateEnded: {
|
||||
[self sliderBtnTouchEnded:self.sliderBtn];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sliderBtnTouchBegin:(UIButton *)btn {
|
||||
if ([self.delegate respondsToSelector:@selector(sliderTouchBegan:)]) {
|
||||
[self.delegate sliderTouchBegan:self.value];
|
||||
}
|
||||
if (self.animate) {
|
||||
[UIView animateWithDuration:kAnimate animations:^{
|
||||
btn.transform = CGAffineTransformMakeScale(1.2, 1.2);
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sliderBtnTouchEnded:(UIButton *)btn {
|
||||
if ([self.delegate respondsToSelector:@selector(sliderTouchEnded:)]) {
|
||||
[self.delegate sliderTouchEnded:self.value];
|
||||
}
|
||||
if (self.animate) {
|
||||
[UIView animateWithDuration:kAnimate animations:^{
|
||||
btn.transform = CGAffineTransformIdentity;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sliderBtnDragMoving:(UIButton *)btn point:(CGPoint)touchPoint {
|
||||
// 点击的位置
|
||||
CGPoint point = touchPoint;
|
||||
// 获取进度值 由于btn是从 0-(self.width - btn.width)
|
||||
CGFloat value = (point.x - btn.zf_width * 0.5) / self.bgProgressView.zf_width;
|
||||
// value的值需在0-1之间
|
||||
value = value >= 1.0 ? 1.0 : value <= 0.0 ? 0.0 : value;
|
||||
if (self.value == value) return;
|
||||
self.isForward = self.value < value;
|
||||
self.value = value;
|
||||
if ([self.delegate respondsToSelector:@selector(sliderValueChanged:)]) {
|
||||
[self.delegate sliderValueChanged:value];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)tapped:(UITapGestureRecognizer *)tap {
|
||||
CGPoint point = [tap locationInView:self.bgProgressView];
|
||||
// 获取进度
|
||||
CGFloat value = (point.x - self.sliderBtn.zf_width * 0.5) * 1.0 / self.bgProgressView.zf_width;
|
||||
value = value >= 1.0 ? 1.0 : value <= 0 ? 0 : value;
|
||||
self.value = value;
|
||||
if ([self.delegate respondsToSelector:@selector(sliderTapped:)]) {
|
||||
[self.delegate sliderTapped:value];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (UIView *)bgProgressView {
|
||||
if (!_bgProgressView) {
|
||||
_bgProgressView = [UIImageView new];
|
||||
_bgProgressView.backgroundColor = [UIColor grayColor];
|
||||
_bgProgressView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_bgProgressView.clipsToBounds = YES;
|
||||
}
|
||||
return _bgProgressView;
|
||||
}
|
||||
|
||||
- (UIView *)bufferProgressView {
|
||||
if (!_bufferProgressView) {
|
||||
_bufferProgressView = [UIImageView new];
|
||||
_bufferProgressView.backgroundColor = [UIColor whiteColor];
|
||||
_bufferProgressView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_bufferProgressView.clipsToBounds = YES;
|
||||
}
|
||||
return _bufferProgressView;
|
||||
}
|
||||
|
||||
- (UIView *)sliderProgressView {
|
||||
if (!_sliderProgressView) {
|
||||
_sliderProgressView = [UIImageView new];
|
||||
_sliderProgressView.backgroundColor = [UIColor redColor];
|
||||
_sliderProgressView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_sliderProgressView.clipsToBounds = YES;
|
||||
}
|
||||
return _sliderProgressView;
|
||||
}
|
||||
|
||||
- (ZFSliderButton *)sliderBtn {
|
||||
if (!_sliderBtn) {
|
||||
_sliderBtn = [ZFSliderButton buttonWithType:UIButtonTypeCustom];
|
||||
[_sliderBtn setAdjustsImageWhenHighlighted:NO];
|
||||
}
|
||||
return _sliderBtn;
|
||||
}
|
||||
|
||||
- (UIView *)loadingBarView {
|
||||
if (!_loadingBarView) {
|
||||
_loadingBarView = [[UIView alloc] init];
|
||||
_loadingBarView.backgroundColor = [UIColor whiteColor];
|
||||
_loadingBarView.hidden = YES;
|
||||
}
|
||||
return _loadingBarView;
|
||||
}
|
||||
|
||||
@end
|
||||
31
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSmallFloatControlView.h
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// ZFSmallFloatControlView.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ZFSmallFloatControlView : UIView
|
||||
|
||||
@property (nonatomic, copy, nullable) void(^closeClickCallback)(void);
|
||||
|
||||
@end
|
||||
72
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSmallFloatControlView.m
generated
Normal file
@@ -0,0 +1,72 @@
|
||||
//
|
||||
// ZFSmallFloatControlView.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFSmallFloatControlView.h"
|
||||
#import "ZFUtilities.h"
|
||||
|
||||
@interface ZFSmallFloatControlView ()
|
||||
|
||||
@property (nonatomic, strong) UIButton *closeBtn;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFSmallFloatControlView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self addSubview:self.closeBtn];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
CGFloat min_x = 0;
|
||||
CGFloat min_y = 0;
|
||||
CGFloat min_w = 0;
|
||||
CGFloat min_h = 0;
|
||||
CGFloat min_view_w = self.bounds.size.width;
|
||||
|
||||
min_x = min_view_w-20;
|
||||
min_y = -10;
|
||||
min_w = 30;
|
||||
min_h = min_w;
|
||||
self.closeBtn.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
}
|
||||
|
||||
- (void)closeBtnClick:(UIButton *)sender {
|
||||
if (self.closeClickCallback) self.closeClickCallback();
|
||||
}
|
||||
|
||||
- (UIButton *)closeBtn {
|
||||
if (!_closeBtn) {
|
||||
_closeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_closeBtn setImage:ZFPlayer_Image(@"ZFPlayer_close") forState:UIControlStateNormal];
|
||||
[_closeBtn addTarget:self action:@selector(closeBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _closeBtn;
|
||||
}
|
||||
|
||||
@end
|
||||
27
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSpeedLoadingView.h
generated
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// ZFSpeedLoadingView.h
|
||||
// Pods-ZFPlayer_Example
|
||||
//
|
||||
// Created by 紫枫 on 2018/6/27.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ZFLoadingView.h"
|
||||
|
||||
@interface ZFSpeedLoadingView : UIView
|
||||
|
||||
@property (nonatomic, strong) ZFLoadingView *loadingView;
|
||||
|
||||
@property (nonatomic, strong) UILabel *speedTextLabel;
|
||||
|
||||
/**
|
||||
* Starts animation of the spinner.
|
||||
*/
|
||||
- (void)startAnimating;
|
||||
|
||||
/**
|
||||
* Stops animation of the spinnner.
|
||||
*/
|
||||
- (void)stopAnimating;
|
||||
|
||||
@end
|
||||
117
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFSpeedLoadingView.m
generated
Normal file
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// ZFSpeedLoadingView.m
|
||||
// Pods-ZFPlayer_Example
|
||||
//
|
||||
// Created by 紫枫 on 2018/6/27.
|
||||
//
|
||||
|
||||
#import "ZFSpeedLoadingView.h"
|
||||
#import "ZFNetworkSpeedMonitor.h"
|
||||
#import "UIView+ZFFrame.h"
|
||||
|
||||
@interface ZFSpeedLoadingView ()
|
||||
|
||||
@property (nonatomic, strong) ZFNetworkSpeedMonitor *speedMonitor;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFSpeedLoadingView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initialize];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
if (self = [super initWithCoder:aDecoder]) {
|
||||
[self initialize];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)awakeFromNib {
|
||||
[super awakeFromNib];
|
||||
[self initialize];
|
||||
}
|
||||
|
||||
- (void)initialize {
|
||||
self.userInteractionEnabled = NO;
|
||||
[self addSubview:self.loadingView];
|
||||
[self addSubview:self.speedTextLabel];
|
||||
[self.speedMonitor startNetworkSpeedMonitor];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkSpeedChanged:) name:ZFDownloadNetworkSpeedNotificationKey object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self.speedMonitor stopNetworkSpeedMonitor];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:ZFDownloadNetworkSpeedNotificationKey object:nil];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
CGFloat min_x = 0;
|
||||
CGFloat min_y = 0;
|
||||
CGFloat min_w = 0;
|
||||
CGFloat min_h = 0;
|
||||
CGFloat min_view_w = self.zf_width;
|
||||
CGFloat min_view_h = self.zf_height;
|
||||
|
||||
min_w = 44;
|
||||
min_h = min_w;
|
||||
min_x = (min_view_w - min_w) / 2;
|
||||
min_y = (min_view_h - min_h) / 2 - 10;
|
||||
self.loadingView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = 0;
|
||||
min_y = self.loadingView.zf_bottom+5;
|
||||
min_w = min_view_w;
|
||||
min_h = 20;
|
||||
self.speedTextLabel.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
}
|
||||
|
||||
- (void)networkSpeedChanged:(NSNotification *)sender {
|
||||
NSString *downloadSpped = [sender.userInfo objectForKey:ZFNetworkSpeedNotificationKey];
|
||||
self.speedTextLabel.text = downloadSpped;
|
||||
}
|
||||
|
||||
- (void)startAnimating {
|
||||
[self.loadingView startAnimating];
|
||||
self.hidden = NO;
|
||||
}
|
||||
|
||||
- (void)stopAnimating {
|
||||
[self.loadingView stopAnimating];
|
||||
self.hidden = YES;
|
||||
}
|
||||
|
||||
- (UILabel *)speedTextLabel {
|
||||
if (!_speedTextLabel) {
|
||||
_speedTextLabel = [UILabel new];
|
||||
_speedTextLabel.textColor = [UIColor whiteColor];
|
||||
_speedTextLabel.font = [UIFont systemFontOfSize:12.0];
|
||||
_speedTextLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _speedTextLabel;
|
||||
}
|
||||
|
||||
- (ZFNetworkSpeedMonitor *)speedMonitor {
|
||||
if (!_speedMonitor) {
|
||||
_speedMonitor = [[ZFNetworkSpeedMonitor alloc] init];
|
||||
}
|
||||
return _speedMonitor;
|
||||
}
|
||||
|
||||
- (ZFLoadingView *)loadingView {
|
||||
if (!_loadingView) {
|
||||
_loadingView = [[ZFLoadingView alloc] init];
|
||||
_loadingView.lineWidth = 0.8;
|
||||
_loadingView.duration = 1;
|
||||
_loadingView.hidesWhenStopped = YES;
|
||||
}
|
||||
return _loadingView;
|
||||
}
|
||||
|
||||
@end
|
||||
52
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFUtilities.h
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// ZFUtilities.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/// iPhoneX iPhoneXS iPhoneXS Max iPhoneXR 机型判断
|
||||
#define iPhoneX ([UIScreen instancesRespondToSelector:@selector(currentMode)] ? ((NSInteger)(([[UIScreen mainScreen] currentMode].size.height/[[UIScreen mainScreen] currentMode].size.width)*100) == 216) : NO)
|
||||
|
||||
#define ZFPlayer_Image(file) [ZFUtilities imageNamed:file]
|
||||
|
||||
// 屏幕的宽
|
||||
#define ZFPlayer_ScreenWidth [[UIScreen mainScreen] bounds].size.width
|
||||
// 屏幕的高
|
||||
#define ZFPlayer_ScreenHeight [[UIScreen mainScreen] bounds].size.height
|
||||
|
||||
#define UIColorFromHex(rgbValue) [UIColor \
|
||||
colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
|
||||
green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
|
||||
blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]
|
||||
|
||||
@interface ZFUtilities : NSObject
|
||||
|
||||
+ (NSString *)convertTimeSecond:(NSInteger)timeSecond;
|
||||
|
||||
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size;
|
||||
|
||||
+ (UIImage *)imageNamed:(NSString *)name;
|
||||
|
||||
@end
|
||||
|
||||
74
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFUtilities.m
generated
Normal file
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// ZFUtilities.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFUtilities.h"
|
||||
|
||||
@implementation ZFUtilities
|
||||
|
||||
+ (NSString *)convertTimeSecond:(NSInteger)timeSecond {
|
||||
NSString *theLastTime = nil;
|
||||
long second = timeSecond;
|
||||
if (timeSecond < 60) {
|
||||
theLastTime = [NSString stringWithFormat:@"00:%02zd", second];
|
||||
} else if(timeSecond >= 60 && timeSecond < 3600){
|
||||
theLastTime = [NSString stringWithFormat:@"%02zd:%02zd", second/60, second%60];
|
||||
} else if(timeSecond >= 3600){
|
||||
theLastTime = [NSString stringWithFormat:@"%02zd:%02zd:%02zd", second/3600, second%3600/60, second%60];
|
||||
}
|
||||
return theLastTime;
|
||||
}
|
||||
|
||||
+ (UIImage *)imageWithColor:(UIColor *)color size:(CGSize)size {
|
||||
if (!color || size.width <= 0 || size.height <= 0) return nil;
|
||||
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
|
||||
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
|
||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||
CGContextSetFillColorWithColor(context, color.CGColor);
|
||||
CGContextFillRect(context, rect);
|
||||
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
|
||||
UIGraphicsEndImageContext();
|
||||
return image;
|
||||
}
|
||||
|
||||
+ (NSBundle *)bundle {
|
||||
static NSBundle *bundle = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
bundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"ZFPlayer" ofType:@"bundle"]];
|
||||
});
|
||||
return bundle;
|
||||
}
|
||||
|
||||
+ (UIImage *)imageNamed:(NSString *)name {
|
||||
if (name.length == 0) return nil;
|
||||
int scale = (int)UIScreen.mainScreen.scale;
|
||||
if (scale < 2) scale = 2;
|
||||
else if (scale > 3) scale = 3;
|
||||
NSString *n = [NSString stringWithFormat:@"%@@%dx", name, scale];
|
||||
UIImage *image = [UIImage imageWithContentsOfFile:[self.bundle pathForResource:n ofType:@"png"]];
|
||||
if (!image) image = [UIImage imageWithContentsOfFile:[self.bundle pathForResource:name ofType:@"png"]];
|
||||
return image;
|
||||
}
|
||||
|
||||
@end
|
||||
46
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFVolumeBrightnessView.h
generated
Normal file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// ZFVolumeBrightnessView.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
typedef NS_ENUM(NSInteger, ZFVolumeBrightnessType) {
|
||||
ZFVolumeBrightnessTypeVolume, // volume
|
||||
ZFVolumeBrightnessTypeumeBrightness // brightness
|
||||
};
|
||||
|
||||
@interface ZFVolumeBrightnessView : UIView
|
||||
|
||||
@property (nonatomic, assign, readonly) ZFVolumeBrightnessType volumeBrightnessType;
|
||||
@property (nonatomic, strong, readonly) UIProgressView *progressView;
|
||||
@property (nonatomic, strong, readonly) UIImageView *iconImageView;
|
||||
|
||||
- (void)updateProgress:(CGFloat)progress withVolumeBrightnessType:(ZFVolumeBrightnessType)volumeBrightnessType;
|
||||
|
||||
/// 添加系统音量view
|
||||
- (void)addSystemVolumeView;
|
||||
|
||||
/// 移除系统音量view
|
||||
- (void)removeSystemVolumeView;
|
||||
|
||||
@end
|
||||
162
Pods/ZFPlayer/ZFPlayer/Classes/ControlView/ZFVolumeBrightnessView.m
generated
Normal file
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// ZFVolumeBrightnessView.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFVolumeBrightnessView.h"
|
||||
#import <MediaPlayer/MediaPlayer.h>
|
||||
#import "ZFUtilities.h"
|
||||
|
||||
@interface ZFVolumeBrightnessView ()
|
||||
|
||||
@property (nonatomic, strong) UIProgressView *progressView;
|
||||
@property (nonatomic, strong) UIImageView *iconImageView;
|
||||
@property (nonatomic, assign) ZFVolumeBrightnessType volumeBrightnessType;
|
||||
@property (nonatomic, strong) MPVolumeView *volumeView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFVolumeBrightnessView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self addSubview:self.iconImageView];
|
||||
[self addSubview:self.progressView];
|
||||
[self hideTipView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self addSystemVolumeView];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
CGFloat min_x = 0;
|
||||
CGFloat min_y = 0;
|
||||
CGFloat min_w = 0;
|
||||
CGFloat min_h = 0;
|
||||
CGFloat min_view_w = self.frame.size.width;
|
||||
CGFloat min_view_h = self.frame.size.height;
|
||||
CGFloat margin = 10;
|
||||
|
||||
min_x = margin;
|
||||
min_w = 20;
|
||||
min_h = min_w;
|
||||
min_y = (min_view_h-min_h)/2;
|
||||
self.iconImageView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
min_x = CGRectGetMaxX(self.iconImageView.frame) + margin;
|
||||
min_h = 2;
|
||||
min_y = (min_view_h-min_h)/2;
|
||||
min_w = min_view_w - min_x - margin;
|
||||
self.progressView.frame = CGRectMake(min_x, min_y, min_w, min_h);
|
||||
|
||||
self.layer.cornerRadius = min_view_h/2;
|
||||
self.layer.masksToBounds = YES;
|
||||
}
|
||||
|
||||
- (void)hideTipView {
|
||||
[UIView animateWithDuration:0.5 animations:^{
|
||||
self.alpha = 0;
|
||||
} completion:^(BOOL finished) {
|
||||
self.hidden = YES;
|
||||
}];
|
||||
}
|
||||
|
||||
/// 添加系统音量view
|
||||
- (void)addSystemVolumeView {
|
||||
[self.volumeView removeFromSuperview];
|
||||
}
|
||||
|
||||
/// 移除系统音量view
|
||||
- (void)removeSystemVolumeView {
|
||||
[[UIApplication sharedApplication].keyWindow addSubview:self.volumeView];
|
||||
}
|
||||
|
||||
- (void)updateProgress:(CGFloat)progress withVolumeBrightnessType:(ZFVolumeBrightnessType)volumeBrightnessType {
|
||||
if (progress >= 1) {
|
||||
progress = 1;
|
||||
} else if (progress <= 0) {
|
||||
progress = 0;
|
||||
}
|
||||
self.progressView.progress = progress;
|
||||
self.volumeBrightnessType = volumeBrightnessType;
|
||||
UIImage *playerImage = nil;
|
||||
if (volumeBrightnessType == ZFVolumeBrightnessTypeVolume) {
|
||||
if (progress == 0) {
|
||||
playerImage = ZFPlayer_Image(@"ZFPlayer_muted");
|
||||
} else if (progress > 0 && progress < 0.5) {
|
||||
playerImage = ZFPlayer_Image(@"ZFPlayer_volume_low");
|
||||
} else {
|
||||
playerImage = ZFPlayer_Image(@"ZFPlayer_volume_high");
|
||||
}
|
||||
} else if (volumeBrightnessType == ZFVolumeBrightnessTypeumeBrightness) {
|
||||
if (progress >= 0 && progress < 0.5) {
|
||||
playerImage = ZFPlayer_Image(@"ZFPlayer_brightness_low");
|
||||
} else {
|
||||
playerImage = ZFPlayer_Image(@"ZFPlayer_brightness_high");
|
||||
}
|
||||
}
|
||||
self.iconImageView.image = playerImage;
|
||||
self.hidden = NO;
|
||||
self.alpha = 1;
|
||||
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideTipView) object:nil];
|
||||
[self performSelector:@selector(hideTipView) withObject:nil afterDelay:1.5];
|
||||
}
|
||||
|
||||
- (void)setVolumeBrightnessType:(ZFVolumeBrightnessType)volumeBrightnessType {
|
||||
_volumeBrightnessType = volumeBrightnessType;
|
||||
if (volumeBrightnessType == ZFVolumeBrightnessTypeVolume) {
|
||||
self.iconImageView.image = ZFPlayer_Image(@"ZFPlayer_volume");
|
||||
} else {
|
||||
self.iconImageView.image = ZFPlayer_Image(@"ZFPlayer_brightness");
|
||||
}
|
||||
}
|
||||
|
||||
- (UIProgressView *)progressView {
|
||||
if (!_progressView) {
|
||||
_progressView = [[UIProgressView alloc] init];
|
||||
_progressView.progressTintColor = [UIColor whiteColor];
|
||||
_progressView.trackTintColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.4];;
|
||||
}
|
||||
return _progressView;
|
||||
}
|
||||
|
||||
- (UIImageView *)iconImageView {
|
||||
if (!_iconImageView) {
|
||||
_iconImageView = [UIImageView new];
|
||||
}
|
||||
return _iconImageView;
|
||||
}
|
||||
|
||||
- (MPVolumeView *)volumeView {
|
||||
if (!_volumeView) {
|
||||
_volumeView = [[MPVolumeView alloc] init];
|
||||
_volumeView.frame = CGRectMake(-1000, -1000, 100, 100);
|
||||
}
|
||||
return _volumeView;
|
||||
}
|
||||
|
||||
@end
|
||||
244
Pods/ZFPlayer/ZFPlayer/Classes/Core/UIScrollView+ZFPlayer.h
generated
Normal file
@@ -0,0 +1,244 @@
|
||||
//
|
||||
// UIScrollView+ZFPlayer.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/*
|
||||
* The scroll direction of scrollView.
|
||||
*/
|
||||
typedef NS_ENUM(NSUInteger, ZFPlayerScrollDirection) {
|
||||
ZFPlayerScrollDirectionNone,
|
||||
ZFPlayerScrollDirectionUp, // Scroll up
|
||||
ZFPlayerScrollDirectionDown, // Scroll Down
|
||||
ZFPlayerScrollDirectionLeft, // Scroll left
|
||||
ZFPlayerScrollDirectionRight // Scroll right
|
||||
};
|
||||
|
||||
/*
|
||||
* The scrollView direction.
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, ZFPlayerScrollViewDirection) {
|
||||
ZFPlayerScrollViewDirectionVertical,
|
||||
ZFPlayerScrollViewDirectionHorizontal
|
||||
};
|
||||
|
||||
/*
|
||||
* The player container type
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, ZFPlayerContainerType) {
|
||||
ZFPlayerContainerTypeView,
|
||||
ZFPlayerContainerTypeCell
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger , ZFPlayerScrollViewScrollPosition) {
|
||||
ZFPlayerScrollViewScrollPositionNone,
|
||||
/// Apply to UITableView and UICollectionViewDirection is vertical scrolling.
|
||||
ZFPlayerScrollViewScrollPositionTop,
|
||||
ZFPlayerScrollViewScrollPositionCenteredVertically,
|
||||
ZFPlayerScrollViewScrollPositionBottom,
|
||||
|
||||
/// Only apply to UICollectionViewDirection is horizontal scrolling.
|
||||
ZFPlayerScrollViewScrollPositionLeft,
|
||||
ZFPlayerScrollViewScrollPositionCenteredHorizontally,
|
||||
ZFPlayerScrollViewScrollPositionRight
|
||||
};
|
||||
|
||||
@interface UIScrollView (ZFPlayer)
|
||||
|
||||
/// When the ZFPlayerScrollViewDirection is ZFPlayerScrollViewDirectionVertical,the property has value.
|
||||
@property (nonatomic, readonly) CGFloat zf_lastOffsetY;
|
||||
|
||||
/// When the ZFPlayerScrollViewDirection is ZFPlayerScrollViewDirectionHorizontal,the property has value.
|
||||
@property (nonatomic, readonly) CGFloat zf_lastOffsetX;
|
||||
|
||||
/// The scrollView scroll direction, default is ZFPlayerScrollViewDirectionVertical.
|
||||
@property (nonatomic) ZFPlayerScrollViewDirection zf_scrollViewDirection;
|
||||
|
||||
/// The scroll direction of scrollView while scrolling.
|
||||
/// When the ZFPlayerScrollViewDirection is ZFPlayerScrollViewDirectionVertical,this value can only be ZFPlayerScrollDirectionUp or ZFPlayerScrollDirectionDown.
|
||||
/// When the ZFPlayerScrollViewDirection is ZFPlayerScrollViewDirectionHorizontal,this value can only be ZFPlayerScrollDirectionLeft or ZFPlayerScrollDirectionRight.
|
||||
@property (nonatomic, readonly) ZFPlayerScrollDirection zf_scrollDirection;
|
||||
|
||||
/// Get the cell according to indexPath.
|
||||
- (UIView *)zf_getCellForIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
/// Get the indexPath for cell.
|
||||
- (NSIndexPath *)zf_getIndexPathForCell:(UIView *)cell;
|
||||
|
||||
/**
|
||||
Scroll to indexPath with position.
|
||||
|
||||
@param indexPath scroll the indexPath.
|
||||
@param scrollPosition scrollView scroll position.
|
||||
@param animated animate.
|
||||
@param completionHandler Scroll completion callback.
|
||||
*/
|
||||
- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
atScrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
|
||||
animated:(BOOL)animated
|
||||
completionHandler:(void (^ __nullable)(void))completionHandler;
|
||||
|
||||
/**
|
||||
Scroll to indexPath with position.
|
||||
|
||||
@param indexPath scroll the indexPath.
|
||||
@param scrollPosition scrollView scroll position.
|
||||
@param duration animate duration.
|
||||
@param completionHandler Scroll completion callback.
|
||||
*/
|
||||
- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
atScrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
|
||||
animateDuration:(NSTimeInterval)duration
|
||||
completionHandler:(void (^ __nullable)(void))completionHandler;
|
||||
|
||||
///------------------------------------
|
||||
/// The following method must be implemented in UIScrollViewDelegate.
|
||||
///------------------------------------
|
||||
|
||||
- (void)zf_scrollViewDidEndDecelerating;
|
||||
|
||||
- (void)zf_scrollViewDidEndDraggingWillDecelerate:(BOOL)decelerate;
|
||||
|
||||
- (void)zf_scrollViewDidScrollToTop;
|
||||
|
||||
- (void)zf_scrollViewDidScroll;
|
||||
|
||||
- (void)zf_scrollViewWillBeginDragging;
|
||||
|
||||
///------------------------------------
|
||||
/// end
|
||||
///------------------------------------
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@interface UIScrollView (ZFPlayerCannotCalled)
|
||||
|
||||
/// The block invoked When the player appearing.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerAppearingInScrollView)(NSIndexPath *indexPath, CGFloat playerApperaPercent);
|
||||
|
||||
/// The block invoked When the player disappearing.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerDisappearingInScrollView)(NSIndexPath *indexPath, CGFloat playerDisapperaPercent);
|
||||
|
||||
/// The block invoked When the player will appeared.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerWillAppearInScrollView)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player did appeared.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerDidAppearInScrollView)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player will disappear.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerWillDisappearInScrollView)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player did disappeared.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerDidDisappearInScrollView)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player did stop scroll.
|
||||
@property (nonatomic, copy, nullable) void(^zf_scrollViewDidEndScrollingCallback)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player did scroll.
|
||||
@property (nonatomic, copy, nullable) void(^zf_scrollViewDidScrollCallback)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player should play.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerShouldPlayInScrollView)(NSIndexPath *indexPath);
|
||||
|
||||
/// The current player scroll slides off the screen percent.
|
||||
/// the property used when the `stopWhileNotVisible` is YES, stop the current playing player.
|
||||
/// the property used when the `stopWhileNotVisible` is NO, the current playing player add to small container view.
|
||||
/// 0.0~1.0, defalut is 0.5.
|
||||
/// 0.0 is the player will disappear.
|
||||
/// 1.0 is the player did disappear.
|
||||
@property (nonatomic) CGFloat zf_playerDisapperaPercent;
|
||||
|
||||
/// The current player scroll to the screen percent to play the video.
|
||||
/// 0.0~1.0, defalut is 0.0.
|
||||
/// 0.0 is the player will appear.
|
||||
/// 1.0 is the player did appear.
|
||||
@property (nonatomic) CGFloat zf_playerApperaPercent;
|
||||
|
||||
/// The current player controller is disappear, not dealloc
|
||||
@property (nonatomic) BOOL zf_viewControllerDisappear;
|
||||
|
||||
/// Has stopped playing
|
||||
@property (nonatomic, assign) BOOL zf_stopPlay;
|
||||
|
||||
/// The currently playing cell stop playing when the cell has out off the screen,defalut is YES.
|
||||
@property (nonatomic, assign) BOOL zf_stopWhileNotVisible;
|
||||
|
||||
/// The indexPath is playing.
|
||||
@property (nonatomic, nullable) NSIndexPath *zf_playingIndexPath;
|
||||
|
||||
/// The indexPath should be play while scrolling.
|
||||
@property (nonatomic, nullable) NSIndexPath *zf_shouldPlayIndexPath;
|
||||
|
||||
/// WWANA networks play automatically,default NO.
|
||||
@property (nonatomic, getter=zf_isWWANAutoPlay) BOOL zf_WWANAutoPlay;
|
||||
|
||||
/// The player should auto player,default is YES.
|
||||
@property (nonatomic) BOOL zf_shouldAutoPlay;
|
||||
|
||||
/// The view tag that the player display in scrollView.
|
||||
@property (nonatomic) NSInteger zf_containerViewTag;
|
||||
|
||||
/// The video contrainerView in normal model.
|
||||
@property (nonatomic, strong) UIView *zf_containerView;
|
||||
|
||||
/// The video contrainerView type.
|
||||
@property (nonatomic, assign) ZFPlayerContainerType zf_containerType;
|
||||
|
||||
/// Filter the cell that should be played when the scroll is stopped (to play when the scroll is stopped).
|
||||
- (void)zf_filterShouldPlayCellWhileScrolled:(void (^ __nullable)(NSIndexPath *indexPath))handler;
|
||||
|
||||
/// Filter the cell that should be played while scrolling (you can use this to filter the highlighted cell).
|
||||
- (void)zf_filterShouldPlayCellWhileScrolling:(void (^ __nullable)(NSIndexPath *indexPath))handler;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIScrollView (ZFPlayerDeprecated)
|
||||
|
||||
/// The block invoked When the player did stop scroll.
|
||||
@property (nonatomic, copy, nullable) void(^zf_scrollViewDidStopScrollCallback)(NSIndexPath *indexPath) __attribute__((deprecated("use `ZFPlayerController.zf_scrollViewDidEndScrollingCallback` instead.")));
|
||||
|
||||
/// The block invoked When the player should play.
|
||||
@property (nonatomic, copy, nullable) void(^zf_shouldPlayIndexPathCallback)(NSIndexPath *indexPath) __attribute__((deprecated("use `ZFPlayerController.zf_playerShouldPlayInScrollView` instead.")));
|
||||
|
||||
|
||||
/// Scroll to indexPath position `ZFPlayerScrollViewScrollPositionTop` with animations.
|
||||
- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
completionHandler:(void (^ __nullable)(void))completionHandler __attribute__((deprecated("use `zf_scrollToRowAtIndexPath:atScrollPosition:animated:completionHandler:` instead.")));
|
||||
|
||||
/// Scroll to indexPath position `ZFPlayerScrollViewScrollPositionTop` with animations.
|
||||
- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
animated:(BOOL)animated
|
||||
completionHandler:(void (^ __nullable)(void))completionHandler __attribute__((deprecated("use `zf_scrollToRowAtIndexPath:atScrollPosition:animated:completionHandler:` instead.")));
|
||||
|
||||
/// Scroll to indexPath position `ZFPlayerScrollViewScrollPositionTop` with animations.
|
||||
- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
animateWithDuration:(NSTimeInterval)duration
|
||||
completionHandler:(void (^ __nullable)(void))completionHandler __attribute__((deprecated("use `zf_scrollToRowAtIndexPath:atScrollPosition:animateDuration:completionHandler:` instead.")));
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
915
Pods/ZFPlayer/ZFPlayer/Classes/Core/UIScrollView+ZFPlayer.m
generated
Normal file
@@ -0,0 +1,915 @@
|
||||
//
|
||||
// UIScrollView+ZFPlayer.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "UIScrollView+ZFPlayer.h"
|
||||
#import <objc/runtime.h>
|
||||
#import "ZFReachabilityManager.h"
|
||||
#import "ZFPlayerConst.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
|
||||
|
||||
@interface UIScrollView ()
|
||||
|
||||
@property (nonatomic) CGFloat zf_lastOffsetY;
|
||||
@property (nonatomic) CGFloat zf_lastOffsetX;
|
||||
@property (nonatomic) ZFPlayerScrollDirection zf_scrollDirection;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIScrollView (ZFPlayer)
|
||||
|
||||
#pragma mark - public method
|
||||
|
||||
- (UIView *)zf_getCellForIndexPath:(NSIndexPath *)indexPath {
|
||||
if ([self _isTableView]) {
|
||||
UITableView *tableView = (UITableView *)self;
|
||||
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
|
||||
return cell;
|
||||
} else if ([self _isCollectionView]) {
|
||||
UICollectionView *collectionView = (UICollectionView *)self;
|
||||
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
|
||||
return cell;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSIndexPath *)zf_getIndexPathForCell:(UIView *)cell {
|
||||
if ([self _isTableView]) {
|
||||
UITableView *tableView = (UITableView *)self;
|
||||
NSIndexPath *indexPath = [tableView indexPathForCell:(UITableViewCell *)cell];
|
||||
return indexPath;
|
||||
} else if ([self _isCollectionView]) {
|
||||
UICollectionView *collectionView = (UICollectionView *)self;
|
||||
NSIndexPath *indexPath = [collectionView indexPathForCell:(UICollectionViewCell *)cell];
|
||||
return indexPath;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
/**
|
||||
Scroll to indexPath with position.
|
||||
|
||||
@param indexPath scroll the indexPath.
|
||||
@param scrollPosition scrollView scroll position.
|
||||
@param animated animate.
|
||||
@param completionHandler Scroll completion callback.
|
||||
*/
|
||||
- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
atScrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
|
||||
animated:(BOOL)animated
|
||||
completionHandler:(void (^ __nullable)(void))completionHandler {
|
||||
[self zf_scrollToRowAtIndexPath:indexPath atScrollPosition:scrollPosition animateDuration:animated ? 0.4 : 0.0 completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
atScrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
|
||||
animateDuration:(NSTimeInterval)duration
|
||||
completionHandler:(void (^ __nullable)(void))completionHandler {
|
||||
BOOL animated = duration > 0.0;
|
||||
if ([self _isTableView]) {
|
||||
UITableView *tableView = (UITableView *)self;
|
||||
UITableViewScrollPosition tableScrollPosition = UITableViewScrollPositionNone;
|
||||
if (scrollPosition <= ZFPlayerScrollViewScrollPositionBottom) {
|
||||
tableScrollPosition = (UITableViewScrollPosition)scrollPosition;
|
||||
}
|
||||
[tableView scrollToRowAtIndexPath:indexPath atScrollPosition:tableScrollPosition animated:animated];
|
||||
} else if ([self _isCollectionView]) {
|
||||
UICollectionView *collectionView = (UICollectionView *)self;
|
||||
if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionVertical) {
|
||||
UICollectionViewScrollPosition collectionScrollPosition = UICollectionViewScrollPositionNone;
|
||||
switch (scrollPosition) {
|
||||
case ZFPlayerScrollViewScrollPositionNone:
|
||||
collectionScrollPosition = UICollectionViewScrollPositionNone;
|
||||
break;
|
||||
case ZFPlayerScrollViewScrollPositionTop:
|
||||
collectionScrollPosition = UICollectionViewScrollPositionTop;
|
||||
break;
|
||||
case ZFPlayerScrollViewScrollPositionCenteredVertically:
|
||||
collectionScrollPosition = UICollectionViewScrollPositionCenteredVertically;
|
||||
break;
|
||||
case ZFPlayerScrollViewScrollPositionBottom:
|
||||
collectionScrollPosition = UICollectionViewScrollPositionBottom;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
[collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:collectionScrollPosition animated:animated];
|
||||
} else if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionHorizontal) {
|
||||
UICollectionViewScrollPosition collectionScrollPosition = UICollectionViewScrollPositionNone;
|
||||
switch (scrollPosition) {
|
||||
case ZFPlayerScrollViewScrollPositionNone:
|
||||
collectionScrollPosition = UICollectionViewScrollPositionNone;
|
||||
break;
|
||||
case ZFPlayerScrollViewScrollPositionLeft:
|
||||
collectionScrollPosition = UICollectionViewScrollPositionLeft;
|
||||
break;
|
||||
case ZFPlayerScrollViewScrollPositionCenteredHorizontally:
|
||||
collectionScrollPosition = UICollectionViewScrollPositionCenteredHorizontally;
|
||||
break;
|
||||
case ZFPlayerScrollViewScrollPositionRight:
|
||||
collectionScrollPosition = UICollectionViewScrollPositionRight;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
[collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:collectionScrollPosition animated:animated];
|
||||
}
|
||||
}
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
||||
if (completionHandler) completionHandler();
|
||||
});
|
||||
}
|
||||
|
||||
- (void)zf_scrollViewDidEndDecelerating {
|
||||
BOOL scrollToScrollStop = !self.tracking && !self.dragging && !self.decelerating;
|
||||
if (scrollToScrollStop) {
|
||||
[self _scrollViewDidStopScroll];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)zf_scrollViewDidEndDraggingWillDecelerate:(BOOL)decelerate {
|
||||
if (!decelerate) {
|
||||
BOOL dragToDragStop = self.tracking && !self.dragging && !self.decelerating;
|
||||
if (dragToDragStop) {
|
||||
[self _scrollViewDidStopScroll];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)zf_scrollViewDidScrollToTop {
|
||||
[self _scrollViewDidStopScroll];
|
||||
}
|
||||
|
||||
- (void)zf_scrollViewDidScroll {
|
||||
if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionVertical) {
|
||||
[self _findCorrectCellWhenScrollViewDirectionVertical:nil];
|
||||
[self _scrollViewScrollingDirectionVertical];
|
||||
} else {
|
||||
[self _findCorrectCellWhenScrollViewDirectionHorizontal:nil];
|
||||
[self _scrollViewScrollingDirectionHorizontal];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)zf_scrollViewWillBeginDragging {
|
||||
[self _scrollViewBeginDragging];
|
||||
}
|
||||
|
||||
#pragma mark - private method
|
||||
|
||||
- (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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The percentage of scrolling processed in vertical scrolling.
|
||||
*/
|
||||
- (void)_scrollViewScrollingDirectionVertical {
|
||||
CGFloat offsetY = self.contentOffset.y;
|
||||
self.zf_scrollDirection = (offsetY - self.zf_lastOffsetY > 0) ? ZFPlayerScrollDirectionUp : ZFPlayerScrollDirectionDown;
|
||||
self.zf_lastOffsetY = offsetY;
|
||||
if (self.zf_stopPlay) return;
|
||||
|
||||
UIView *playerView;
|
||||
if (self.zf_containerType == ZFPlayerContainerTypeCell) {
|
||||
// Avoid being paused the first time you play it.
|
||||
if (self.contentOffset.y < 0) return;
|
||||
if (!self.zf_playingIndexPath) return;
|
||||
|
||||
UIView *cell = [self zf_getCellForIndexPath:self.zf_playingIndexPath];
|
||||
if (!cell) {
|
||||
if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
|
||||
return;
|
||||
}
|
||||
playerView = [cell viewWithTag:self.zf_containerViewTag];
|
||||
} else if (self.zf_containerType == ZFPlayerContainerTypeView) {
|
||||
if (!self.zf_containerView) return;
|
||||
playerView = self.zf_containerView;
|
||||
}
|
||||
|
||||
CGRect rect1 = [playerView convertRect:playerView.frame toView:self];
|
||||
CGRect rect = [self convertRect:rect1 toView:self.superview];
|
||||
/// playerView top to scrollView top space.
|
||||
CGFloat topSpacing = CGRectGetMinY(rect) - CGRectGetMinY(self.frame) - CGRectGetMinY(playerView.frame);
|
||||
/// playerView bottom to scrollView bottom space.
|
||||
CGFloat bottomSpacing = CGRectGetMaxY(self.frame) - CGRectGetMaxY(rect) + CGRectGetMinY(playerView.frame);
|
||||
/// The height of the content area.
|
||||
CGFloat contentInsetHeight = CGRectGetMaxY(self.frame) - CGRectGetMinY(self.frame);
|
||||
|
||||
CGFloat playerDisapperaPercent = 0;
|
||||
CGFloat playerApperaPercent = 0;
|
||||
|
||||
if (self.zf_scrollDirection == ZFPlayerScrollDirectionUp) { /// Scroll up
|
||||
/// Player is disappearing.
|
||||
if (topSpacing <= 0 && CGRectGetHeight(rect) != 0) {
|
||||
playerDisapperaPercent = -topSpacing/CGRectGetHeight(rect);
|
||||
if (playerDisapperaPercent > 1.0) playerDisapperaPercent = 1.0;
|
||||
if (self.zf_playerDisappearingInScrollView) self.zf_playerDisappearingInScrollView(self.zf_playingIndexPath, playerDisapperaPercent);
|
||||
}
|
||||
|
||||
/// Top area
|
||||
if (topSpacing <= 0 && topSpacing > -CGRectGetHeight(rect)/2) {
|
||||
/// When the player will disappear.
|
||||
if (self.zf_playerWillDisappearInScrollView) self.zf_playerWillDisappearInScrollView(self.zf_playingIndexPath);
|
||||
} else if (topSpacing <= -CGRectGetHeight(rect)) {
|
||||
/// When the player did disappeared.
|
||||
if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
|
||||
} else if (topSpacing > 0 && topSpacing <= contentInsetHeight) {
|
||||
/// Player is appearing.
|
||||
if (CGRectGetHeight(rect) != 0) {
|
||||
playerApperaPercent = -(topSpacing-contentInsetHeight)/CGRectGetHeight(rect);
|
||||
if (playerApperaPercent > 1.0) playerApperaPercent = 1.0;
|
||||
if (self.zf_playerAppearingInScrollView) self.zf_playerAppearingInScrollView(self.zf_playingIndexPath, playerApperaPercent);
|
||||
}
|
||||
/// In visable area
|
||||
if (topSpacing <= contentInsetHeight && topSpacing > contentInsetHeight-CGRectGetHeight(rect)/2) {
|
||||
/// When the player will appear.
|
||||
if (self.zf_playerWillAppearInScrollView) self.zf_playerWillAppearInScrollView(self.zf_playingIndexPath);
|
||||
} else {
|
||||
/// When the player did appeared.
|
||||
if (self.zf_playerDidAppearInScrollView) self.zf_playerDidAppearInScrollView(self.zf_playingIndexPath);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (self.zf_scrollDirection == ZFPlayerScrollDirectionDown) { /// Scroll Down
|
||||
/// Player is disappearing.
|
||||
if (bottomSpacing <= 0 && CGRectGetHeight(rect) != 0) {
|
||||
playerDisapperaPercent = -bottomSpacing/CGRectGetHeight(rect);
|
||||
if (playerDisapperaPercent > 1.0) playerDisapperaPercent = 1.0;
|
||||
if (self.zf_playerDisappearingInScrollView) self.zf_playerDisappearingInScrollView(self.zf_playingIndexPath, playerDisapperaPercent);
|
||||
}
|
||||
|
||||
/// Bottom area
|
||||
if (bottomSpacing <= 0 && bottomSpacing > -CGRectGetHeight(rect)/2) {
|
||||
/// When the player will disappear.
|
||||
if (self.zf_playerWillDisappearInScrollView) self.zf_playerWillDisappearInScrollView(self.zf_playingIndexPath);
|
||||
} else if (bottomSpacing <= -CGRectGetHeight(rect)) {
|
||||
/// When the player did disappeared.
|
||||
if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
|
||||
} else if (bottomSpacing > 0 && bottomSpacing <= contentInsetHeight) {
|
||||
/// Player is appearing.
|
||||
if (CGRectGetHeight(rect) != 0) {
|
||||
playerApperaPercent = -(bottomSpacing-contentInsetHeight)/CGRectGetHeight(rect);
|
||||
if (playerApperaPercent > 1.0) playerApperaPercent = 1.0;
|
||||
if (self.zf_playerAppearingInScrollView) self.zf_playerAppearingInScrollView(self.zf_playingIndexPath, playerApperaPercent);
|
||||
}
|
||||
/// In visable area
|
||||
if (bottomSpacing <= contentInsetHeight && bottomSpacing > contentInsetHeight-CGRectGetHeight(rect)/2) {
|
||||
/// When the player will appear.
|
||||
if (self.zf_playerWillAppearInScrollView) self.zf_playerWillAppearInScrollView(self.zf_playingIndexPath);
|
||||
} else {
|
||||
/// When the player did appeared.
|
||||
if (self.zf_playerDidAppearInScrollView) self.zf_playerDidAppearInScrollView(self.zf_playingIndexPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The percentage of scrolling processed in horizontal scrolling.
|
||||
*/
|
||||
- (void)_scrollViewScrollingDirectionHorizontal {
|
||||
CGFloat offsetX = self.contentOffset.x;
|
||||
self.zf_scrollDirection = (offsetX - self.zf_lastOffsetX > 0) ? ZFPlayerScrollDirectionLeft : ZFPlayerScrollDirectionRight;
|
||||
self.zf_lastOffsetX = offsetX;
|
||||
if (self.zf_stopPlay) return;
|
||||
|
||||
UIView *playerView;
|
||||
if (self.zf_containerType == ZFPlayerContainerTypeCell) {
|
||||
// Avoid being paused the first time you play it.
|
||||
if (self.contentOffset.x < 0) return;
|
||||
if (!self.zf_playingIndexPath) return;
|
||||
|
||||
UIView *cell = [self zf_getCellForIndexPath:self.zf_playingIndexPath];
|
||||
if (!cell) {
|
||||
if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
|
||||
return;
|
||||
}
|
||||
playerView = [cell viewWithTag:self.zf_containerViewTag];
|
||||
} else if (self.zf_containerType == ZFPlayerContainerTypeView) {
|
||||
if (!self.zf_containerView) return;
|
||||
playerView = self.zf_containerView;
|
||||
}
|
||||
|
||||
CGRect rect1 = [playerView convertRect:playerView.frame toView:self];
|
||||
CGRect rect = [self convertRect:rect1 toView:self.superview];
|
||||
/// playerView left to scrollView left space.
|
||||
CGFloat leftSpacing = CGRectGetMinX(rect) - CGRectGetMinX(self.frame) - CGRectGetMinX(playerView.frame);
|
||||
/// playerView bottom to scrollView right space.
|
||||
CGFloat rightSpacing = CGRectGetMaxX(self.frame) - CGRectGetMaxX(rect) + CGRectGetMinX(playerView.frame);
|
||||
/// The height of the content area.
|
||||
CGFloat contentInsetWidth = CGRectGetMaxX(self.frame) - CGRectGetMinX(self.frame);
|
||||
|
||||
CGFloat playerDisapperaPercent = 0;
|
||||
CGFloat playerApperaPercent = 0;
|
||||
|
||||
if (self.zf_scrollDirection == ZFPlayerScrollDirectionLeft) { /// Scroll left
|
||||
/// Player is disappearing.
|
||||
if (leftSpacing <= 0 && CGRectGetWidth(rect) != 0) {
|
||||
playerDisapperaPercent = -leftSpacing/CGRectGetWidth(rect);
|
||||
if (playerDisapperaPercent > 1.0) playerDisapperaPercent = 1.0;
|
||||
if (self.zf_playerDisappearingInScrollView) self.zf_playerDisappearingInScrollView(self.zf_playingIndexPath, playerDisapperaPercent);
|
||||
}
|
||||
|
||||
/// Top area
|
||||
if (leftSpacing <= 0 && leftSpacing > -CGRectGetWidth(rect)/2) {
|
||||
/// When the player will disappear.
|
||||
if (self.zf_playerWillDisappearInScrollView) self.zf_playerWillDisappearInScrollView(self.zf_playingIndexPath);
|
||||
} else if (leftSpacing <= -CGRectGetWidth(rect)) {
|
||||
/// When the player did disappeared.
|
||||
if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
|
||||
} else if (leftSpacing > 0 && leftSpacing <= contentInsetWidth) {
|
||||
/// Player is appearing.
|
||||
if (CGRectGetWidth(rect) != 0) {
|
||||
playerApperaPercent = -(leftSpacing-contentInsetWidth)/CGRectGetWidth(rect);
|
||||
if (playerApperaPercent > 1.0) playerApperaPercent = 1.0;
|
||||
if (self.zf_playerAppearingInScrollView) self.zf_playerAppearingInScrollView(self.zf_playingIndexPath, playerApperaPercent);
|
||||
}
|
||||
/// In visable area
|
||||
if (leftSpacing <= contentInsetWidth && leftSpacing > contentInsetWidth-CGRectGetWidth(rect)/2) {
|
||||
/// When the player will appear.
|
||||
if (self.zf_playerWillAppearInScrollView) self.zf_playerWillAppearInScrollView(self.zf_playingIndexPath);
|
||||
} else {
|
||||
/// When the player did appeared.
|
||||
if (self.zf_playerDidAppearInScrollView) self.zf_playerDidAppearInScrollView(self.zf_playingIndexPath);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (self.zf_scrollDirection == ZFPlayerScrollDirectionRight) { /// Scroll right
|
||||
/// Player is disappearing.
|
||||
if (rightSpacing <= 0 && CGRectGetWidth(rect) != 0) {
|
||||
playerDisapperaPercent = -rightSpacing/CGRectGetWidth(rect);
|
||||
if (playerDisapperaPercent > 1.0) playerDisapperaPercent = 1.0;
|
||||
if (self.zf_playerDisappearingInScrollView) self.zf_playerDisappearingInScrollView(self.zf_playingIndexPath, playerDisapperaPercent);
|
||||
}
|
||||
|
||||
/// Bottom area
|
||||
if (rightSpacing <= 0 && rightSpacing > -CGRectGetWidth(rect)/2) {
|
||||
/// When the player will disappear.
|
||||
if (self.zf_playerWillDisappearInScrollView) self.zf_playerWillDisappearInScrollView(self.zf_playingIndexPath);
|
||||
} else if (rightSpacing <= -CGRectGetWidth(rect)) {
|
||||
/// When the player did disappeared.
|
||||
if (self.zf_playerDidDisappearInScrollView) self.zf_playerDidDisappearInScrollView(self.zf_playingIndexPath);
|
||||
} else if (rightSpacing > 0 && rightSpacing <= contentInsetWidth) {
|
||||
/// Player is appearing.
|
||||
if (CGRectGetWidth(rect) != 0) {
|
||||
playerApperaPercent = -(rightSpacing-contentInsetWidth)/CGRectGetWidth(rect);
|
||||
if (playerApperaPercent > 1.0) playerApperaPercent = 1.0;
|
||||
if (self.zf_playerAppearingInScrollView) self.zf_playerAppearingInScrollView(self.zf_playingIndexPath, playerApperaPercent);
|
||||
}
|
||||
/// In visable area
|
||||
if (rightSpacing <= contentInsetWidth && rightSpacing > contentInsetWidth-CGRectGetWidth(rect)/2) {
|
||||
/// When the player will appear.
|
||||
if (self.zf_playerWillAppearInScrollView) self.zf_playerWillAppearInScrollView(self.zf_playingIndexPath);
|
||||
} else {
|
||||
/// When the player did appeared.
|
||||
if (self.zf_playerDidAppearInScrollView) self.zf_playerDidAppearInScrollView(self.zf_playingIndexPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Find the playing cell while the scrollDirection is vertical.
|
||||
*/
|
||||
- (void)_findCorrectCellWhenScrollViewDirectionVertical:(void (^ __nullable)(NSIndexPath *indexPath))handler {
|
||||
if (!self.zf_shouldAutoPlay) return;
|
||||
if (self.zf_containerType == ZFPlayerContainerTypeView) return;
|
||||
|
||||
if (!self.zf_stopWhileNotVisible) {
|
||||
/// If you have a cell that is playing, stop the traversal.
|
||||
if (self.zf_playingIndexPath) {
|
||||
NSIndexPath *finalIndexPath = self.zf_playingIndexPath;
|
||||
if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(finalIndexPath);
|
||||
if (handler) handler(finalIndexPath);
|
||||
self.zf_shouldPlayIndexPath = finalIndexPath;
|
||||
return;
|
||||
}
|
||||
}
|
||||
NSArray *visiableCells = nil;
|
||||
NSIndexPath *indexPath = nil;
|
||||
BOOL isLast = self.contentOffset.y + self.frame.size.height >= self.contentSize.height;
|
||||
if ([self _isTableView]) {
|
||||
UITableView *tableView = (UITableView *)self;
|
||||
visiableCells = [tableView visibleCells];
|
||||
// First visible cell indexPath
|
||||
indexPath = tableView.indexPathsForVisibleRows.firstObject;
|
||||
if ((self.contentOffset.y <= 0 || isLast) && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
|
||||
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
|
||||
UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
|
||||
if (playerView && !playerView.hidden && playerView.alpha > 0.01) {
|
||||
if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
|
||||
if (handler) handler(indexPath);
|
||||
self.zf_shouldPlayIndexPath = indexPath;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ([self _isCollectionView]) {
|
||||
UICollectionView *collectionView = (UICollectionView *)self;
|
||||
visiableCells = [collectionView visibleCells];
|
||||
NSArray *sortedIndexPaths = [collectionView.indexPathsForVisibleItems sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
|
||||
return [obj1 compare:obj2];
|
||||
}];
|
||||
|
||||
visiableCells = [visiableCells sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
|
||||
NSIndexPath *path1 = (NSIndexPath *)[collectionView indexPathForCell:obj1];
|
||||
NSIndexPath *path2 = (NSIndexPath *)[collectionView indexPathForCell:obj2];
|
||||
return [path1 compare:path2];
|
||||
}];
|
||||
|
||||
// First visible cell indexPath
|
||||
indexPath = isLast ? sortedIndexPaths.lastObject : sortedIndexPaths.firstObject;
|
||||
if ((self.contentOffset.y <= 0 || isLast) && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
|
||||
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
|
||||
UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
|
||||
if (playerView && !playerView.hidden && playerView.alpha > 0.01) {
|
||||
if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
|
||||
if (handler) handler(indexPath);
|
||||
self.zf_shouldPlayIndexPath = indexPath;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSArray *cells = nil;
|
||||
if (self.zf_scrollDirection == ZFPlayerScrollDirectionUp) {
|
||||
cells = visiableCells;
|
||||
} else {
|
||||
cells = [visiableCells reverseObjectEnumerator].allObjects;
|
||||
}
|
||||
|
||||
/// Mid line.
|
||||
CGFloat scrollViewMidY = CGRectGetHeight(self.frame)/2;
|
||||
/// The final playing indexPath.
|
||||
__block NSIndexPath *finalIndexPath = nil;
|
||||
/// The final distance from the center line.
|
||||
__block CGFloat finalSpace = 0;
|
||||
@zf_weakify(self)
|
||||
[cells enumerateObjectsUsingBlock:^(UIView *cell, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
@zf_strongify(self)
|
||||
UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
|
||||
if (!playerView || playerView.hidden || playerView.alpha <= 0.01) return;
|
||||
CGRect rect1 = [playerView convertRect:playerView.frame toView:self];
|
||||
CGRect rect = [self convertRect:rect1 toView:self.superview];
|
||||
/// playerView top to scrollView top space.
|
||||
CGFloat topSpacing = CGRectGetMinY(rect) - CGRectGetMinY(self.frame) - CGRectGetMinY(playerView.frame);
|
||||
/// playerView bottom to scrollView bottom space.
|
||||
CGFloat bottomSpacing = CGRectGetMaxY(self.frame) - CGRectGetMaxY(rect) + CGRectGetMinY(playerView.frame);
|
||||
CGFloat centerSpacing = ABS(scrollViewMidY - CGRectGetMidY(rect));
|
||||
NSIndexPath *indexPath = [self zf_getIndexPathForCell:cell];
|
||||
|
||||
/// Play when the video playback section is visible.
|
||||
if ((topSpacing >= -(1 - self.zf_playerApperaPercent) * CGRectGetHeight(rect)) && (bottomSpacing >= -(1 - self.zf_playerApperaPercent) * CGRectGetHeight(rect))) {
|
||||
if (!finalIndexPath || centerSpacing < finalSpace) {
|
||||
finalIndexPath = indexPath;
|
||||
finalSpace = centerSpacing;
|
||||
}
|
||||
}
|
||||
}];
|
||||
/// if find the playing indexPath.
|
||||
if (finalIndexPath) {
|
||||
if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
|
||||
if (handler) handler(finalIndexPath);
|
||||
}
|
||||
self.zf_shouldPlayIndexPath = finalIndexPath;
|
||||
}
|
||||
|
||||
/**
|
||||
Find the playing cell while the scrollDirection is horizontal.
|
||||
*/
|
||||
- (void)_findCorrectCellWhenScrollViewDirectionHorizontal:(void (^ __nullable)(NSIndexPath *indexPath))handler {
|
||||
if (!self.zf_shouldAutoPlay) return;
|
||||
if (self.zf_containerType == ZFPlayerContainerTypeView) return;
|
||||
if (!self.zf_stopWhileNotVisible) {
|
||||
/// If you have a cell that is playing, stop the traversal.
|
||||
if (self.zf_playingIndexPath) {
|
||||
NSIndexPath *finalIndexPath = self.zf_playingIndexPath;
|
||||
if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(finalIndexPath);
|
||||
if (handler) handler(finalIndexPath);
|
||||
self.zf_shouldPlayIndexPath = finalIndexPath;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NSArray *visiableCells = nil;
|
||||
NSIndexPath *indexPath = nil;
|
||||
BOOL isLast = self.contentOffset.x + self.frame.size.width >= self.contentSize.width;
|
||||
if ([self _isTableView]) {
|
||||
UITableView *tableView = (UITableView *)self;
|
||||
visiableCells = [tableView visibleCells];
|
||||
// First visible cell indexPath
|
||||
indexPath = tableView.indexPathsForVisibleRows.firstObject;
|
||||
if ((self.contentOffset.x <= 0 || isLast) && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
|
||||
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
|
||||
UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
|
||||
if (playerView && !playerView.hidden && playerView.alpha > 0.01) {
|
||||
if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
|
||||
if (handler) handler(indexPath);
|
||||
self.zf_shouldPlayIndexPath = indexPath;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if ([self _isCollectionView]) {
|
||||
UICollectionView *collectionView = (UICollectionView *)self;
|
||||
visiableCells = [collectionView visibleCells];
|
||||
NSArray *sortedIndexPaths = [collectionView.indexPathsForVisibleItems sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
|
||||
return [obj1 compare:obj2];
|
||||
}];
|
||||
|
||||
visiableCells = [visiableCells sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
|
||||
NSIndexPath *path1 = (NSIndexPath *)[collectionView indexPathForCell:obj1];
|
||||
NSIndexPath *path2 = (NSIndexPath *)[collectionView indexPathForCell:obj2];
|
||||
return [path1 compare:path2];
|
||||
}];
|
||||
|
||||
// First visible cell indexPath
|
||||
indexPath = isLast ? sortedIndexPaths.lastObject : sortedIndexPaths.firstObject;
|
||||
if ((self.contentOffset.x <= 0 || isLast) && (!self.zf_playingIndexPath || [indexPath compare:self.zf_playingIndexPath] == NSOrderedSame)) {
|
||||
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
|
||||
UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
|
||||
if (playerView && !playerView.hidden && playerView.alpha > 0.01) {
|
||||
if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
|
||||
if (handler) handler(indexPath);
|
||||
self.zf_shouldPlayIndexPath = indexPath;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSArray *cells = nil;
|
||||
if (self.zf_scrollDirection == ZFPlayerScrollDirectionUp) {
|
||||
cells = visiableCells;
|
||||
} else {
|
||||
cells = [visiableCells reverseObjectEnumerator].allObjects;
|
||||
}
|
||||
|
||||
/// Mid line.
|
||||
CGFloat scrollViewMidX = CGRectGetWidth(self.frame)/2;
|
||||
/// The final playing indexPath.
|
||||
__block NSIndexPath *finalIndexPath = nil;
|
||||
/// The final distance from the center line.
|
||||
__block CGFloat finalSpace = 0;
|
||||
@zf_weakify(self)
|
||||
[cells enumerateObjectsUsingBlock:^(UIView *cell, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
@zf_strongify(self)
|
||||
UIView *playerView = [cell viewWithTag:self.zf_containerViewTag];
|
||||
if (!playerView || playerView.hidden || playerView.alpha <= 0.01) return;
|
||||
CGRect rect1 = [playerView convertRect:playerView.frame toView:self];
|
||||
CGRect rect = [self convertRect:rect1 toView:self.superview];
|
||||
/// playerView left to scrollView top space.
|
||||
CGFloat leftSpacing = CGRectGetMinX(rect) - CGRectGetMinX(self.frame) - CGRectGetMinX(playerView.frame);
|
||||
/// playerView right to scrollView top space.
|
||||
CGFloat rightSpacing = CGRectGetMaxX(self.frame) - CGRectGetMaxX(rect) + CGRectGetMinX(playerView.frame);
|
||||
CGFloat centerSpacing = ABS(scrollViewMidX - CGRectGetMidX(rect));
|
||||
NSIndexPath *indexPath = [self zf_getIndexPathForCell:cell];
|
||||
|
||||
/// Play when the video playback section is visible.
|
||||
if ((leftSpacing >= -(1 - self.zf_playerApperaPercent) * CGRectGetWidth(rect)) && (rightSpacing >= -(1 - self.zf_playerApperaPercent) * CGRectGetWidth(rect))) {
|
||||
if (!finalIndexPath || centerSpacing < finalSpace) {
|
||||
finalIndexPath = indexPath;
|
||||
finalSpace = centerSpacing;
|
||||
}
|
||||
}
|
||||
}];
|
||||
/// if find the playing indexPath.
|
||||
if (finalIndexPath) {
|
||||
if (self.zf_scrollViewDidScrollCallback) self.zf_scrollViewDidScrollCallback(indexPath);
|
||||
if (handler) handler(finalIndexPath);
|
||||
self.zf_shouldPlayIndexPath = finalIndexPath;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)_isTableView {
|
||||
return [self isKindOfClass:[UITableView class]];
|
||||
}
|
||||
|
||||
- (BOOL)_isCollectionView {
|
||||
return [self isKindOfClass:[UICollectionView class]];
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (ZFPlayerScrollDirection)zf_scrollDirection {
|
||||
return [objc_getAssociatedObject(self, _cmd) integerValue];
|
||||
}
|
||||
|
||||
- (ZFPlayerScrollViewDirection)zf_scrollViewDirection {
|
||||
return [objc_getAssociatedObject(self, _cmd) integerValue];
|
||||
}
|
||||
|
||||
- (CGFloat)zf_lastOffsetY {
|
||||
return [objc_getAssociatedObject(self, _cmd) floatValue];
|
||||
}
|
||||
|
||||
- (CGFloat)zf_lastOffsetX {
|
||||
return [objc_getAssociatedObject(self, _cmd) floatValue];
|
||||
}
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (void)setZf_scrollDirection:(ZFPlayerScrollDirection)zf_scrollDirection {
|
||||
objc_setAssociatedObject(self, @selector(zf_scrollDirection), @(zf_scrollDirection), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_scrollViewDirection:(ZFPlayerScrollViewDirection)zf_scrollViewDirection {
|
||||
objc_setAssociatedObject(self, @selector(zf_scrollViewDirection), @(zf_scrollViewDirection), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_lastOffsetY:(CGFloat)zf_lastOffsetY {
|
||||
objc_setAssociatedObject(self, @selector(zf_lastOffsetY), @(zf_lastOffsetY), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_lastOffsetX:(CGFloat)zf_lastOffsetX {
|
||||
objc_setAssociatedObject(self, @selector(zf_lastOffsetX), @(zf_lastOffsetX), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIScrollView (ZFPlayerCannotCalled)
|
||||
|
||||
- (void)zf_filterShouldPlayCellWhileScrolling:(void (^ __nullable)(NSIndexPath *indexPath))handler {
|
||||
if (self.zf_scrollViewDirection == ZFPlayerScrollViewDirectionVertical) {
|
||||
[self _findCorrectCellWhenScrollViewDirectionVertical:handler];
|
||||
} else {
|
||||
[self _findCorrectCellWhenScrollViewDirectionHorizontal:handler];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)zf_filterShouldPlayCellWhileScrolled:(void (^ __nullable)(NSIndexPath *indexPath))handler {
|
||||
if (!self.zf_shouldAutoPlay) return;
|
||||
@zf_weakify(self)
|
||||
[self zf_filterShouldPlayCellWhileScrolling:^(NSIndexPath *indexPath) {
|
||||
@zf_strongify(self)
|
||||
/// 如果当前控制器已经消失,直接return
|
||||
if (self.zf_viewControllerDisappear) return;
|
||||
if ([ZFReachabilityManager sharedManager].isReachableViaWWAN && !self.zf_WWANAutoPlay) {
|
||||
/// 移动网络
|
||||
self.zf_shouldPlayIndexPath = indexPath;
|
||||
return;
|
||||
}
|
||||
if (handler) handler(indexPath);
|
||||
self.zf_playingIndexPath = indexPath;
|
||||
}];
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull, CGFloat))zf_playerDisappearingInScrollView {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull, CGFloat))zf_playerAppearingInScrollView {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull))zf_playerDidAppearInScrollView {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull))zf_playerWillDisappearInScrollView {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull))zf_playerWillAppearInScrollView {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull))zf_playerDidDisappearInScrollView {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidEndScrollingCallback {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidScrollCallback {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull))zf_playerShouldPlayInScrollView {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (CGFloat)zf_playerApperaPercent {
|
||||
return [objc_getAssociatedObject(self, _cmd) floatValue];
|
||||
}
|
||||
|
||||
- (CGFloat)zf_playerDisapperaPercent {
|
||||
return [objc_getAssociatedObject(self, _cmd) floatValue];
|
||||
}
|
||||
|
||||
- (BOOL)zf_viewControllerDisappear {
|
||||
return [objc_getAssociatedObject(self, _cmd) boolValue];
|
||||
}
|
||||
|
||||
- (BOOL)zf_stopPlay {
|
||||
NSNumber *number = objc_getAssociatedObject(self, _cmd);
|
||||
if (number) return number.boolValue;
|
||||
self.zf_stopPlay = YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)zf_stopWhileNotVisible {
|
||||
return [objc_getAssociatedObject(self, _cmd) boolValue];
|
||||
}
|
||||
|
||||
- (NSIndexPath *)zf_playingIndexPath {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (NSIndexPath *)zf_shouldPlayIndexPath {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (NSInteger)zf_containerViewTag {
|
||||
return [objc_getAssociatedObject(self, _cmd) integerValue];
|
||||
}
|
||||
|
||||
- (BOOL)zf_isWWANAutoPlay {
|
||||
return [objc_getAssociatedObject(self, _cmd) boolValue];
|
||||
}
|
||||
|
||||
- (BOOL)zf_shouldAutoPlay {
|
||||
NSNumber *number = objc_getAssociatedObject(self, _cmd);
|
||||
if (number) return number.boolValue;
|
||||
self.zf_shouldAutoPlay = YES;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (ZFPlayerContainerType)zf_containerType {
|
||||
return [objc_getAssociatedObject(self, _cmd) integerValue];
|
||||
}
|
||||
|
||||
- (UIView *)zf_containerView {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (void)setZf_playerDisappearingInScrollView:(void (^)(NSIndexPath * _Nonnull, CGFloat))zf_playerDisappearingInScrollView {
|
||||
objc_setAssociatedObject(self, @selector(zf_playerDisappearingInScrollView), zf_playerDisappearingInScrollView, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_playerAppearingInScrollView:(void (^)(NSIndexPath * _Nonnull, CGFloat))zf_playerAppearingInScrollView {
|
||||
objc_setAssociatedObject(self, @selector(zf_playerAppearingInScrollView), zf_playerAppearingInScrollView, 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_scrollViewDidEndScrollingCallback:(void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidEndScrollingCallback {
|
||||
objc_setAssociatedObject(self, @selector(zf_scrollViewDidEndScrollingCallback), zf_scrollViewDidEndScrollingCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_scrollViewDidScrollCallback:(void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidScrollCallback {
|
||||
objc_setAssociatedObject(self, @selector(zf_scrollViewDidScrollCallback), zf_scrollViewDidScrollCallback, 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_playerApperaPercent:(CGFloat)zf_playerApperaPercent {
|
||||
objc_setAssociatedObject(self, @selector(zf_playerApperaPercent), @(zf_playerApperaPercent), OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_playerDisapperaPercent:(CGFloat)zf_playerDisapperaPercent {
|
||||
objc_setAssociatedObject(self, @selector(zf_playerDisapperaPercent), @(zf_playerDisapperaPercent), OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_viewControllerDisappear:(BOOL)zf_viewControllerDisappear {
|
||||
objc_setAssociatedObject(self, @selector(zf_viewControllerDisappear), @(zf_viewControllerDisappear), OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_stopPlay:(BOOL)zf_stopPlay {
|
||||
objc_setAssociatedObject(self, @selector(zf_stopPlay), @(zf_stopPlay), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_stopWhileNotVisible:(BOOL)zf_stopWhileNotVisible {
|
||||
objc_setAssociatedObject(self, @selector(zf_stopWhileNotVisible), @(zf_stopWhileNotVisible), 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;
|
||||
}
|
||||
}
|
||||
|
||||
- (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_containerViewTag:(NSInteger)zf_containerViewTag {
|
||||
objc_setAssociatedObject(self, @selector(zf_containerViewTag), @(zf_containerViewTag), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_containerType:(ZFPlayerContainerType)zf_containerType {
|
||||
objc_setAssociatedObject(self, @selector(zf_containerType), @(zf_containerType), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_containerView:(UIView *)zf_containerView {
|
||||
objc_setAssociatedObject(self, @selector(zf_containerView), zf_containerView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_shouldAutoPlay:(BOOL)zf_shouldAutoPlay {
|
||||
objc_setAssociatedObject(self, @selector(zf_shouldAutoPlay), @(zf_shouldAutoPlay), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_WWANAutoPlay:(BOOL)zf_WWANAutoPlay {
|
||||
objc_setAssociatedObject(self, @selector(zf_isWWANAutoPlay), @(zf_WWANAutoPlay), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation UIScrollView (ZFPlayerDeprecated)
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidStopScrollCallback {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
- (void (^)(NSIndexPath * _Nonnull))zf_shouldPlayIndexPathCallback {
|
||||
return objc_getAssociatedObject(self, _cmd);
|
||||
}
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (void)setZf_scrollViewDidStopScrollCallback:(void (^)(NSIndexPath * _Nonnull))zf_scrollViewDidStopScrollCallback {
|
||||
objc_setAssociatedObject(self, @selector(zf_scrollViewDidStopScrollCallback), zf_scrollViewDidStopScrollCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
- (void)setZf_shouldPlayIndexPathCallback:(void (^)(NSIndexPath * _Nonnull))zf_shouldPlayIndexPathCallback {
|
||||
objc_setAssociatedObject(self, @selector(zf_shouldPlayIndexPathCallback), zf_shouldPlayIndexPathCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
}
|
||||
|
||||
#pragma mark - method
|
||||
|
||||
- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath completionHandler:(void (^ __nullable)(void))completionHandler {
|
||||
[self zf_scrollToRowAtIndexPath:indexPath animated:YES completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated completionHandler:(void (^ __nullable)(void))completionHandler {
|
||||
[self zf_scrollToRowAtIndexPath:indexPath animateWithDuration:animated ? 0.4 : 0.0 completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
/// Scroll to indexPath with animations duration.
|
||||
- (void)zf_scrollToRowAtIndexPath:(NSIndexPath *)indexPath animateWithDuration:(NSTimeInterval)duration completionHandler:(void (^ __nullable)(void))completionHandler {
|
||||
[self zf_scrollToRowAtIndexPath:indexPath atScrollPosition:ZFPlayerScrollViewScrollPositionTop animateDuration:duration completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
159
Pods/ZFPlayer/ZFPlayer/Classes/Core/UIViewController+ZFPlayerRotation.m
generated
Normal file
@@ -0,0 +1,159 @@
|
||||
//
|
||||
// UIViewController+ZFPlayerRotation.m
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <objc/runtime.h>
|
||||
#import "ZFLandscapeWindow.h"
|
||||
#import "ZFLandscapeRotationManager.h"
|
||||
|
||||
API_AVAILABLE(ios(13.0)) @implementation UIViewController (ZFPlayerFixSafeArea)
|
||||
|
||||
/// Hook
|
||||
- (void)zf_setContentOverlayInsets:(UIEdgeInsets)insets andLeftMargin:(CGFloat)leftMargin rightMargin:(CGFloat)rightMargin {
|
||||
UIWindow *keyWindow = UIApplication.sharedApplication.keyWindow;
|
||||
UIWindow *otherWindow = self.view.window;
|
||||
if ([keyWindow isKindOfClass:ZFLandscapeWindow.class] && otherWindow != nil) {
|
||||
ZFLandscapeRotationManager *manager = ((ZFLandscapeWindow *)keyWindow).rotationManager;
|
||||
UIWindow *superviewWindow = manager.containerView.window;
|
||||
if (superviewWindow != otherWindow) {
|
||||
[self zf_setContentOverlayInsets:insets andLeftMargin:leftMargin rightMargin:rightMargin];
|
||||
}
|
||||
} else {
|
||||
[self zf_setContentOverlayInsets:insets andLeftMargin:leftMargin rightMargin:rightMargin];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UITabBarController (ZFPlayerRotation)
|
||||
|
||||
+ (void)initialize {
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
SEL selectors[] = {
|
||||
@selector(selectedIndex)
|
||||
};
|
||||
|
||||
for (NSUInteger index = 0; index < sizeof(selectors) / sizeof(SEL); ++index) {
|
||||
SEL originalSelector = selectors[index];
|
||||
SEL swizzledSelector = NSSelectorFromString([@"zf_" stringByAppendingString:NSStringFromSelector(originalSelector)]);
|
||||
[self hookClass:self.class originalSelector:originalSelector swizzledSelector:swizzledSelector];
|
||||
}
|
||||
|
||||
double systemVersion = [UIDevice currentDevice].systemVersion.doubleValue;
|
||||
if (systemVersion >= 13.0 && systemVersion < 16.0) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wundeclared-selector"
|
||||
/// _setContentOverlayInsets:andLeftMargin:rightMargin:
|
||||
NSData *data = [NSData.alloc initWithBase64EncodedString:@"X3NldENvbnRlbnRPdmVybGF5SW5zZXRzOmFuZExlZnRNYXJnaW46cmlnaHRNYXJnaW46" options:kNilOptions];
|
||||
NSString *method = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
SEL originalSelector = NSSelectorFromString(method);
|
||||
#pragma clang diagnostic pop
|
||||
SEL swizzledSelector = @selector(zf_setContentOverlayInsets:andLeftMargin:rightMargin:);
|
||||
|
||||
[self hookClass:UIViewController.class originalSelector:originalSelector swizzledSelector:swizzledSelector];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+ (void)hookClass:(Class)cls originalSelector:(SEL)orlSelector swizzledSelector:(SEL)swzdSelector {
|
||||
Method originalMethod = class_getInstanceMethod(cls, orlSelector);
|
||||
Method swizzledMethod = class_getInstanceMethod(cls, swzdSelector);
|
||||
if (class_addMethod(self, orlSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))) {
|
||||
class_replaceMethod(self, swzdSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
|
||||
} else {
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)zf_selectedIndex {
|
||||
NSInteger index = [self zf_selectedIndex];
|
||||
if (index > self.viewControllers.count) return 0;
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the root view of the window is a UINavigationController, you call this Category first, and then UIViewController called.
|
||||
* All you need to do is revisit the following three methods on a page that supports directions other than portrait.
|
||||
*/
|
||||
|
||||
// Whether automatic screen rotation is supported.
|
||||
- (BOOL)shouldAutorotate {
|
||||
return [[self viewControllerRotation] shouldAutorotate];
|
||||
}
|
||||
|
||||
// Which screen directions are supported.
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return [[self viewControllerRotation] supportedInterfaceOrientations];
|
||||
}
|
||||
|
||||
// The default screen direction (the current ViewController must be represented by a modal UIViewController (which is not valid with modal navigation) to call this method).
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
return [[self viewControllerRotation] preferredInterfaceOrientationForPresentation];
|
||||
}
|
||||
|
||||
// Return ViewController which decide rotation,if selected in UITabBarController is UINavigationController,return topViewController
|
||||
- (UIViewController *)viewControllerRotation {
|
||||
UIViewController *vc = self.viewControllers[self.selectedIndex];
|
||||
if ([vc isKindOfClass:[UINavigationController class]]) {
|
||||
UINavigationController *nav = (UINavigationController *)vc;
|
||||
return nav.topViewController;
|
||||
} else {
|
||||
return vc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@implementation UINavigationController (ZFPlayerRotation)
|
||||
|
||||
/**
|
||||
* If the root view of the window is a UINavigationController, you call this Category first, and then UIViewController called.
|
||||
* All you need to do is revisit the following three methods on a page that supports directions other than portrait.
|
||||
*/
|
||||
|
||||
// Whether automatic screen rotation is supported
|
||||
- (BOOL)shouldAutorotate {
|
||||
return [self.topViewController shouldAutorotate];
|
||||
}
|
||||
|
||||
// Which screen directions are supported
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return [self.topViewController supportedInterfaceOrientations];
|
||||
}
|
||||
|
||||
// The default screen direction (the current ViewController must be represented by a modal UIViewController (which is not valid with modal navigation) to call this method).
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
return [self.topViewController preferredInterfaceOrientationForPresentation];
|
||||
}
|
||||
|
||||
- (UIViewController *)childViewControllerForStatusBarStyle {
|
||||
return self.topViewController;
|
||||
}
|
||||
|
||||
- (UIViewController *)childViewControllerForStatusBarHidden {
|
||||
return self.topViewController;
|
||||
}
|
||||
|
||||
@end
|
||||
35
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFFloatView.h
generated
Executable file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// ZFFloatView.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ZFFloatView : UIView
|
||||
|
||||
/// The parent View
|
||||
@property(nonatomic, weak) UIView *parentView;
|
||||
|
||||
/// Safe margins, mainly for those with Navbar and tabbar
|
||||
@property(nonatomic, assign) UIEdgeInsets safeInsets;
|
||||
|
||||
@end
|
||||
85
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFFloatView.m
generated
Executable file
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// ZFFloatView.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFFloatView.h"
|
||||
|
||||
@implementation ZFFloatView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self initilize];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
|
||||
self = [super initWithCoder:aDecoder];
|
||||
if (self) {
|
||||
[self initilize];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initilize {
|
||||
self.safeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
|
||||
UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(doMoveAction:)];
|
||||
[self addGestureRecognizer:panGestureRecognizer];
|
||||
}
|
||||
|
||||
- (void)setParentView:(UIView *)parentView {
|
||||
_parentView = parentView;
|
||||
[parentView addSubview:self];
|
||||
}
|
||||
|
||||
#pragma mark - Action
|
||||
|
||||
- (void)doMoveAction:(UIPanGestureRecognizer *)recognizer {
|
||||
/// The position where the gesture is moving in the self.view.
|
||||
CGPoint translation = [recognizer translationInView:self.parentView];
|
||||
CGPoint newCenter = CGPointMake(recognizer.view.center.x + translation.x,
|
||||
recognizer.view.center.y + translation.y);
|
||||
|
||||
// Limited screen range:
|
||||
// Top margin limit.
|
||||
newCenter.y = MAX(recognizer.view.frame.size.height/2 + self.safeInsets.top, newCenter.y);
|
||||
|
||||
// Bottom margin limit.
|
||||
newCenter.y = MIN(self.parentView.frame.size.height - self.safeInsets.bottom - recognizer.view.frame.size.height/2, newCenter.y);
|
||||
|
||||
// Left margin limit.
|
||||
newCenter.x = MAX(recognizer.view.frame.size.width/2, newCenter.x);
|
||||
|
||||
// Right margin limit.
|
||||
newCenter.x = MIN(self.parentView.frame.size.width - recognizer.view.frame.size.width/2,newCenter.x);
|
||||
|
||||
// Set the center point.
|
||||
recognizer.view.center = newCenter;
|
||||
|
||||
// Set the gesture coordinates to 0, otherwise it will add up.
|
||||
[recognizer setTranslation:CGPointZero inView:self.parentView];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
40
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFKVOController.h
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// UIScrollView+ZFPlayer.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface ZFKVOController : NSObject
|
||||
|
||||
- (instancetype)initWithTarget:(NSObject *)target;
|
||||
|
||||
- (void)safelyAddObserver:(NSObject *)observer
|
||||
forKeyPath:(NSString *)keyPath
|
||||
options:(NSKeyValueObservingOptions)options
|
||||
context:(void *)context;
|
||||
- (void)safelyRemoveObserver:(NSObject *)observer
|
||||
forKeyPath:(NSString *)keyPath;
|
||||
|
||||
- (void)safelyRemoveAllObservers;
|
||||
|
||||
@end
|
||||
130
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFKVOController.m
generated
Normal file
@@ -0,0 +1,130 @@
|
||||
//
|
||||
// UIScrollView+ZFPlayer.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFKVOController.h"
|
||||
|
||||
@interface ZFKVOEntry : NSObject
|
||||
@property (nonatomic, weak) NSObject *observer;
|
||||
@property (nonatomic, copy) NSString *keyPath;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFKVOEntry
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFKVOController ()
|
||||
@property (nonatomic, weak) NSObject *target;
|
||||
@property (nonatomic, strong) NSMutableArray *observerArray;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFKVOController
|
||||
|
||||
- (instancetype)initWithTarget:(NSObject *)target {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_target = target;
|
||||
_observerArray = [[NSMutableArray alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)safelyAddObserver:(NSObject *)observer
|
||||
forKeyPath:(NSString *)keyPath
|
||||
options:(NSKeyValueObservingOptions)options
|
||||
context:(void *)context {
|
||||
if (_target == nil) return;
|
||||
|
||||
NSInteger indexEntry = [self indexEntryOfObserver:observer forKeyPath:keyPath];
|
||||
if (indexEntry != NSNotFound) {
|
||||
// duplicated register
|
||||
NSLog(@"duplicated observer");
|
||||
} else {
|
||||
@try {
|
||||
[_target addObserver:observer
|
||||
forKeyPath:keyPath
|
||||
options:options
|
||||
context:context];
|
||||
|
||||
ZFKVOEntry *entry = [[ZFKVOEntry alloc] init];
|
||||
entry.observer = observer;
|
||||
entry.keyPath = keyPath;
|
||||
[_observerArray addObject:entry];
|
||||
} @catch (NSException *e) {
|
||||
NSLog(@"ZFKVO: failed to add observer for %@\n", keyPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)safelyRemoveObserver:(NSObject *)observer
|
||||
forKeyPath:(NSString *)keyPath {
|
||||
if (_target == nil) return;
|
||||
|
||||
NSInteger indexEntry = [self indexEntryOfObserver:observer forKeyPath:keyPath];
|
||||
if (indexEntry == NSNotFound) {
|
||||
// duplicated register
|
||||
NSLog(@"duplicated observer");
|
||||
} else {
|
||||
[_observerArray removeObjectAtIndex:indexEntry];
|
||||
@try {
|
||||
[_target removeObserver:observer
|
||||
forKeyPath:keyPath];
|
||||
} @catch (NSException *e) {
|
||||
NSLog(@"ZFKVO: failed to remove observer for %@\n", keyPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)safelyRemoveAllObservers {
|
||||
if (_target == nil) return;
|
||||
[_observerArray enumerateObjectsUsingBlock:^(ZFKVOEntry *entry, NSUInteger idx, BOOL *stop) {
|
||||
if (entry == nil) return;
|
||||
NSObject *observer = entry.observer;
|
||||
if (observer == nil) return;
|
||||
@try {
|
||||
[_target removeObserver:observer
|
||||
forKeyPath:entry.keyPath];
|
||||
} @catch (NSException *e) {
|
||||
NSLog(@"ZFKVO: failed to remove observer for %@\n", entry.keyPath);
|
||||
}
|
||||
}];
|
||||
|
||||
[_observerArray removeAllObjects];
|
||||
}
|
||||
|
||||
- (NSInteger)indexEntryOfObserver:(NSObject *)observer
|
||||
forKeyPath:(NSString *)keyPath {
|
||||
__block NSInteger foundIndex = NSNotFound;
|
||||
[_observerArray enumerateObjectsUsingBlock:^(ZFKVOEntry *entry, NSUInteger idx, BOOL *stop) {
|
||||
if (entry.observer == observer &&
|
||||
[entry.keyPath isEqualToString:keyPath]) {
|
||||
foundIndex = idx;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
return foundIndex;
|
||||
}
|
||||
|
||||
@end
|
||||
86
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeRotationManager.h
generated
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// ZFLandscapeRotationManager.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ZFOrientationObserver.h"
|
||||
#import "ZFLandscapeWindow.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ZFLandscapeRotationManager : NSObject
|
||||
|
||||
/// The block invoked When player will rotate.
|
||||
@property (nonatomic, copy, nullable) void(^orientationWillChange)(UIInterfaceOrientation orientation);
|
||||
|
||||
/// The block invoked when player rotated.
|
||||
@property (nonatomic, copy, nullable) void(^orientationDidChanged)(UIInterfaceOrientation orientation);
|
||||
|
||||
@property (nonatomic, weak) UIView *contentView;
|
||||
|
||||
@property (nonatomic, weak) UIView *containerView;
|
||||
|
||||
@property (nonatomic, strong, nullable) ZFLandscapeWindow *window;
|
||||
|
||||
/// Whether allow the video orientation rotate.
|
||||
/// default is YES.
|
||||
@property (nonatomic, assign) BOOL allowOrientationRotation;
|
||||
|
||||
/// Lock screen orientation
|
||||
@property (nonatomic, getter=isLockedScreen) BOOL lockedScreen;
|
||||
|
||||
@property (nonatomic, assign) BOOL disableAnimations;
|
||||
|
||||
/// The support Interface Orientation,default is ZFInterfaceOrientationMaskAllButUpsideDown
|
||||
@property (nonatomic, assign) ZFInterfaceOrientationMask supportInterfaceOrientation;
|
||||
|
||||
/// The current orientation of the player.
|
||||
/// Default is UIInterfaceOrientationPortrait.
|
||||
@property (nonatomic, assign) UIInterfaceOrientation currentOrientation;
|
||||
|
||||
@property (nonatomic, strong, readonly, nullable) ZFLandscapeViewController *landscapeViewController;
|
||||
|
||||
/// current device orientation observer is activie.
|
||||
@property (nonatomic, assign) BOOL activeDeviceObserver;
|
||||
|
||||
- (void)interfaceOrientation:(UIInterfaceOrientation)orientation completion:(void(^ __nullable)(void))completion;
|
||||
|
||||
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated;
|
||||
|
||||
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated completion:(void(^ __nullable)(void))completion;
|
||||
|
||||
- (UIInterfaceOrientation)getCurrentOrientation;
|
||||
|
||||
- (void)handleDeviceOrientationChange;
|
||||
|
||||
/// update the rotateView and containerView.
|
||||
- (void)updateRotateView:(ZFPlayerView *)rotateView
|
||||
containerView:(UIView *)containerView;
|
||||
|
||||
- (BOOL)isSuppprtInterfaceOrientation:(UIInterfaceOrientation)orientation;
|
||||
|
||||
+ (ZFInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
165
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeRotationManager.m
generated
Normal file
@@ -0,0 +1,165 @@
|
||||
//
|
||||
// ZFLandscapeRotationManager.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLandscapeRotationManager.h"
|
||||
|
||||
@interface ZFLandscapeRotationManager () <ZFLandscapeViewControllerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFLandscapeRotationManager
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_currentOrientation = UIInterfaceOrientationPortrait;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updateRotateView:(ZFPlayerView *)rotateView
|
||||
containerView:(UIView *)containerView {
|
||||
self.contentView = rotateView;
|
||||
self.containerView = containerView;
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientation)getCurrentOrientation {
|
||||
if (@available(iOS 16.0, *)) {
|
||||
NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
|
||||
UIWindowScene *scene = [array firstObject];
|
||||
return scene.interfaceOrientation;
|
||||
} else {
|
||||
return (UIInterfaceOrientation)[UIDevice currentDevice].orientation;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)handleDeviceOrientationChange {
|
||||
if (!self.allowOrientationRotation || self.isLockedScreen) return;
|
||||
if (!UIDeviceOrientationIsValidInterfaceOrientation([UIDevice currentDevice].orientation)) {
|
||||
return;
|
||||
}
|
||||
UIInterfaceOrientation currentOrientation = (UIInterfaceOrientation)[UIDevice currentDevice].orientation;
|
||||
|
||||
// Determine that if the current direction is the same as the direction you want to rotate, do nothing
|
||||
if (currentOrientation == _currentOrientation) return;
|
||||
_currentOrientation = currentOrientation;
|
||||
if (currentOrientation == UIInterfaceOrientationPortraitUpsideDown) return;
|
||||
|
||||
switch (currentOrientation) {
|
||||
case UIInterfaceOrientationPortrait: {
|
||||
if ([self _isSupportedPortrait]) {
|
||||
[self rotateToOrientation:UIInterfaceOrientationPortrait animated:YES];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UIInterfaceOrientationLandscapeLeft: {
|
||||
if ([self _isSupportedLandscapeLeft]) {
|
||||
[self rotateToOrientation:UIInterfaceOrientationLandscapeLeft animated:YES];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UIInterfaceOrientationLandscapeRight: {
|
||||
if ([self _isSupportedLandscapeRight]) {
|
||||
[self rotateToOrientation:UIInterfaceOrientationLandscapeRight animated:YES];
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isSuppprtInterfaceOrientation:(UIInterfaceOrientation)orientation {
|
||||
if (orientation == UIInterfaceOrientationPortrait) {
|
||||
return [self _isSupportedPortrait];
|
||||
} else if (orientation == UIInterfaceOrientationLandscapeLeft) {
|
||||
return [self _isSupportedLandscapeLeft];
|
||||
} else if (orientation == UIInterfaceOrientationLandscapeRight) {
|
||||
return [self _isSupportedLandscapeRight];
|
||||
} else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
|
||||
return [self _isSupportedPortraitUpsideDown];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)interfaceOrientation:(UIInterfaceOrientation)orientation completion:(void(^ __nullable)(void))completion {}
|
||||
|
||||
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated {
|
||||
[self rotateToOrientation:orientation animated:animated completion:nil];
|
||||
}
|
||||
|
||||
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated completion:(void(^ __nullable)(void))completion {
|
||||
_currentOrientation = orientation;
|
||||
if (UIInterfaceOrientationIsLandscape(orientation)) {
|
||||
if (!self.window) {
|
||||
self.window = [ZFLandscapeWindow new];
|
||||
self.landscapeViewController.delegate = self;
|
||||
self.window.rootViewController = self.landscapeViewController;
|
||||
self.window.rotationManager = self;
|
||||
}
|
||||
}
|
||||
self.disableAnimations = !animated;
|
||||
|
||||
if ([UIDevice currentDevice].systemVersion.doubleValue < 16.0) {
|
||||
[self interfaceOrientation:UIInterfaceOrientationUnknown completion:nil];
|
||||
}
|
||||
[self interfaceOrientation:orientation completion:completion];
|
||||
}
|
||||
|
||||
/// is support portrait
|
||||
- (BOOL)_isSupportedPortrait {
|
||||
return self.supportInterfaceOrientation & ZFInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
|
||||
/// is support portraitUpsideDown
|
||||
- (BOOL)_isSupportedPortraitUpsideDown {
|
||||
return self.supportInterfaceOrientation & ZFInterfaceOrientationMaskPortraitUpsideDown;
|
||||
}
|
||||
|
||||
/// is support landscapeLeft
|
||||
- (BOOL)_isSupportedLandscapeLeft {
|
||||
return self.supportInterfaceOrientation & ZFInterfaceOrientationMaskLandscapeLeft;
|
||||
}
|
||||
|
||||
/// is support landscapeRight
|
||||
- (BOOL)_isSupportedLandscapeRight {
|
||||
return self.supportInterfaceOrientation & ZFInterfaceOrientationMaskLandscapeRight;
|
||||
}
|
||||
|
||||
+ (ZFInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window {
|
||||
if ([window isKindOfClass:ZFLandscapeWindow.class]) {
|
||||
ZFLandscapeRotationManager *manager = ((ZFLandscapeWindow *)window).rotationManager;
|
||||
if (manager != nil) {
|
||||
return (ZFInterfaceOrientationMask)[manager supportedInterfaceOrientationsForWindow:window];
|
||||
}
|
||||
}
|
||||
return ZFInterfaceOrientationMaskUnknow;
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window {
|
||||
@throw [NSException exceptionWithName:NSInternalInconsistencyException
|
||||
reason:[NSString stringWithFormat:@"You must override %@ in a subclass.", NSStringFromSelector(_cmd)]
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
33
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeRotationManager_iOS15.h
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// ZFLandscapeRotationManager_iOS15.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLandscapeRotationManager.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ZFLandscapeRotationManager_iOS15 : ZFLandscapeRotationManager
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
166
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeRotationManager_iOS15.m
generated
Normal file
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// ZFLandscapeRotationManager_iOS15.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLandscapeRotationManager_iOS15.h"
|
||||
#import "ZFLandscapeViewController_iOS15.h"
|
||||
|
||||
@interface ZFLandscapeRotationManager_iOS15 () {
|
||||
void(^_rotateCompleted)(void);
|
||||
}
|
||||
|
||||
@property (nonatomic, strong, readonly) ZFLandscapeViewController_iOS15 *landscapeViewController;
|
||||
/// Force Rotaion, default NO.
|
||||
@property (nonatomic, assign) BOOL forceRotaion;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFLandscapeRotationManager_iOS15
|
||||
@synthesize landscapeViewController = _landscapeViewController;
|
||||
|
||||
- (ZFLandscapeViewController_iOS15 *)landscapeViewController {
|
||||
if (!_landscapeViewController) {
|
||||
_landscapeViewController = [[ZFLandscapeViewController_iOS15 alloc] init];
|
||||
}
|
||||
return _landscapeViewController;
|
||||
}
|
||||
|
||||
- (void)interfaceOrientation:(UIInterfaceOrientation)orientation completion:(void(^ __nullable)(void))completion {
|
||||
[super interfaceOrientation:orientation completion:completion];
|
||||
_rotateCompleted = completion;
|
||||
self.forceRotaion = YES;
|
||||
if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {
|
||||
SEL selector = NSSelectorFromString(@"setOrientation:");
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
|
||||
[invocation setSelector:selector];
|
||||
[invocation setTarget:[UIDevice currentDevice]];
|
||||
UIInterfaceOrientation val = orientation;
|
||||
[invocation setArgument:&val atIndex:2];
|
||||
[invocation invoke];
|
||||
}
|
||||
[UIViewController attemptRotationToDeviceOrientation];
|
||||
}
|
||||
|
||||
- (void)rotationBegin {
|
||||
if (self.window.isHidden) {
|
||||
self.window.hidden = NO;
|
||||
[self.window makeKeyAndVisible];
|
||||
}
|
||||
[self.window.rootViewController setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
|
||||
- (void)rotationEnd {
|
||||
if (!self.window.isHidden && !UIInterfaceOrientationIsLandscape(self.currentOrientation)) {
|
||||
self.window.hidden = YES;
|
||||
[self.containerView.window makeKeyAndVisible];
|
||||
}
|
||||
self.disableAnimations = NO;
|
||||
if (_rotateCompleted) {
|
||||
_rotateCompleted();
|
||||
_rotateCompleted = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)allowsRotation {
|
||||
if (UIDeviceOrientationIsValidInterfaceOrientation([UIDevice currentDevice].orientation)) {
|
||||
UIInterfaceOrientation toOrientation = (UIInterfaceOrientation)[UIDevice currentDevice].orientation;
|
||||
if (![self isSuppprtInterfaceOrientation:toOrientation]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
if (self.forceRotaion) { return YES; }
|
||||
if (!self.activeDeviceObserver) { return NO; }
|
||||
if (self.allowOrientationRotation && !self.isLockedScreen) { return YES; }
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - ZFLandscapeViewControllerDelegate
|
||||
|
||||
- (BOOL)ls_shouldAutorotate {
|
||||
if ([self allowsRotation]) {
|
||||
[self rotationBegin];
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)rotationFullscreenViewController:(ZFLandscapeViewController *)viewController viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
||||
UIInterfaceOrientation toOrientation = (UIInterfaceOrientation)[UIDevice currentDevice].orientation;
|
||||
if (![self isSuppprtInterfaceOrientation:toOrientation]) { return; }
|
||||
self.currentOrientation = toOrientation;
|
||||
UIView *playerSuperview = self.landscapeViewController.playerSuperview;
|
||||
if (UIInterfaceOrientationIsLandscape(toOrientation) && self.contentView.superview != playerSuperview) {
|
||||
CGRect targetRect = [self.containerView convertRect:self.containerView.bounds toView:self.containerView.window];
|
||||
playerSuperview.frame = targetRect;
|
||||
self.contentView.frame = playerSuperview.bounds;
|
||||
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[playerSuperview addSubview:self.contentView];
|
||||
[self.contentView layoutIfNeeded];
|
||||
}
|
||||
|
||||
if (self.orientationWillChange) self.orientationWillChange(toOrientation);
|
||||
if (self.disableAnimations) {
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
}
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
if (UIInterfaceOrientationIsLandscape(toOrientation)) {
|
||||
playerSuperview.frame = CGRectMake(0, 0, size.width, size.height);
|
||||
} else {
|
||||
playerSuperview.frame = [self.containerView convertRect:self.containerView.bounds toView:self.containerView.window];
|
||||
}
|
||||
[self.contentView layoutIfNeeded];
|
||||
} completion:^(BOOL finished) {
|
||||
if (self.disableAnimations) {
|
||||
[CATransaction commit];
|
||||
}
|
||||
self.forceRotaion = NO;
|
||||
if (toOrientation == UIInterfaceOrientationPortrait) {
|
||||
UIView *snapshot = [self.contentView snapshotViewAfterScreenUpdates:NO];
|
||||
snapshot.frame = self.containerView.bounds;
|
||||
snapshot.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self.containerView addSubview:snapshot];
|
||||
[UIView animateWithDuration:0.0 animations:^{} completion:^(BOOL finished) {
|
||||
self.contentView.frame = self.containerView.bounds;
|
||||
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
[self.containerView addSubview:self.contentView];
|
||||
[self.contentView layoutIfNeeded];
|
||||
[snapshot removeFromSuperview];
|
||||
[self rotationEnd];
|
||||
if (self.orientationDidChanged) self.orientationDidChanged(toOrientation);
|
||||
}];
|
||||
} else {
|
||||
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
self.contentView.frame = self.window.bounds;
|
||||
[self.contentView layoutIfNeeded];
|
||||
[self rotationEnd];
|
||||
if (self.orientationDidChanged) self.orientationDidChanged(toOrientation);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(UIWindow *)window {
|
||||
return UIInterfaceOrientationMaskAllButUpsideDown;
|
||||
}
|
||||
|
||||
@end
|
||||
33
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeRotationManager_iOS16.h
generated
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// ZFLandscapeRotationManager_iOS16.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLandscapeRotationManager.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ZFLandscapeRotationManager_iOS16 : ZFLandscapeRotationManager
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
147
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeRotationManager_iOS16.m
generated
Normal file
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// ZFLandscapeRotationManager_iOS16.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLandscapeRotationManager_iOS16.h"
|
||||
|
||||
@implementation ZFLandscapeRotationManager_iOS16
|
||||
@synthesize landscapeViewController = _landscapeViewController;
|
||||
|
||||
- (ZFLandscapeViewController *)landscapeViewController {
|
||||
if (!_landscapeViewController) {
|
||||
_landscapeViewController = [[ZFLandscapeViewController alloc] init];
|
||||
}
|
||||
return _landscapeViewController;
|
||||
}
|
||||
|
||||
- (void)setNeedsUpdateOfSupportedInterfaceOrientations {
|
||||
if (@available(iOS 16.0, *)) {
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 160000
|
||||
[UIApplication.sharedApplication.keyWindow.rootViewController setNeedsUpdateOfSupportedInterfaceOrientations];
|
||||
[self.window.rootViewController setNeedsUpdateOfSupportedInterfaceOrientations];
|
||||
#else
|
||||
[(id)UIApplication.sharedApplication.keyWindow.rootViewController setNeedsUpdateOfSupportedInterfaceOrientations];
|
||||
[(id)self.window.rootViewController setNeedsUpdateOfSupportedInterfaceOrientations];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
- (void)interfaceOrientation:(UIInterfaceOrientation)orientation completion:(void(^ __nullable)(void))completion {
|
||||
[super interfaceOrientation:orientation completion:completion];
|
||||
UIInterfaceOrientation fromOrientation = [self getCurrentOrientation];
|
||||
UIInterfaceOrientation toOrientation = orientation;
|
||||
|
||||
UIWindow *sourceWindow = self.containerView.window;
|
||||
CGRect sourceFrame = [self.containerView convertRect:self.containerView.bounds toView:sourceWindow];
|
||||
CGRect screenBounds = UIScreen.mainScreen.bounds;
|
||||
CGFloat maxSize = MAX(screenBounds.size.width, screenBounds.size.height);
|
||||
CGFloat minSize = MIN(screenBounds.size.width, screenBounds.size.height);
|
||||
|
||||
self.contentView.autoresizingMask = UIViewAutoresizingNone;
|
||||
if (fromOrientation == UIInterfaceOrientationPortrait || self.contentView.superview != self.landscapeViewController.view) {
|
||||
self.contentView.frame = sourceFrame;
|
||||
[sourceWindow addSubview:self.contentView];
|
||||
[self.contentView layoutIfNeeded];
|
||||
if (!self.window.isKeyWindow) {
|
||||
self.window.hidden = NO;
|
||||
[self.window makeKeyAndVisible];
|
||||
}
|
||||
} else if (toOrientation == UIInterfaceOrientationPortrait) {
|
||||
self.contentView.bounds = CGRectMake(0, 0, maxSize, minSize);
|
||||
self.contentView.center = CGPointMake(minSize * 0.5, maxSize * 0.5);
|
||||
self.contentView.transform = [self getRotationTransform:fromOrientation];
|
||||
[sourceWindow addSubview:self.contentView];
|
||||
[sourceWindow makeKeyAndVisible];
|
||||
[self.contentView layoutIfNeeded];
|
||||
self.window.hidden = YES;
|
||||
}
|
||||
[self setNeedsUpdateOfSupportedInterfaceOrientations];
|
||||
|
||||
CGRect rotationBounds = CGRectZero;
|
||||
CGPoint rotationCenter = CGPointZero;
|
||||
|
||||
if (UIInterfaceOrientationIsLandscape(toOrientation)) {
|
||||
rotationBounds = CGRectMake(0, 0, maxSize, minSize);
|
||||
rotationCenter = (fromOrientation == UIInterfaceOrientationPortrait || self.contentView.superview != self.landscapeViewController.view) ? CGPointMake(minSize * 0.5, maxSize * 0.5): CGPointMake(maxSize * 0.5, minSize * 0.5);
|
||||
}
|
||||
|
||||
// transform
|
||||
CGAffineTransform rotationTransform = CGAffineTransformIdentity;
|
||||
if (fromOrientation == UIInterfaceOrientationPortrait) {
|
||||
rotationTransform = [self getRotationTransform:toOrientation];
|
||||
}
|
||||
|
||||
self.currentOrientation = toOrientation;
|
||||
if (self.orientationWillChange) self.orientationWillChange(toOrientation);
|
||||
if (self.disableAnimations) {
|
||||
[CATransaction begin];
|
||||
[CATransaction setDisableActions:YES];
|
||||
}
|
||||
[UIView animateWithDuration:0.3 animations:^{
|
||||
if (toOrientation == UIInterfaceOrientationPortrait) {
|
||||
[self.contentView setTransform:rotationTransform];
|
||||
self.contentView.frame = sourceFrame;
|
||||
} else {
|
||||
[self.contentView setTransform:rotationTransform];
|
||||
[self.contentView setBounds:rotationBounds];
|
||||
[self.contentView setCenter:rotationCenter];
|
||||
}
|
||||
[self.contentView layoutIfNeeded];
|
||||
} completion:^(BOOL finished) {
|
||||
if (self.disableAnimations) {
|
||||
[CATransaction commit];
|
||||
}
|
||||
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
if (toOrientation == UIInterfaceOrientationPortrait) {
|
||||
[self.containerView addSubview:self.contentView];
|
||||
self.contentView.frame = self.containerView.bounds;
|
||||
} else {
|
||||
[self setNeedsUpdateOfSupportedInterfaceOrientations];
|
||||
self.contentView.transform = CGAffineTransformIdentity;
|
||||
[self.landscapeViewController.view addSubview:self.contentView];
|
||||
self.contentView.frame = self.window.bounds;
|
||||
[self.contentView layoutIfNeeded];
|
||||
}
|
||||
if (self.orientationDidChanged) self.orientationDidChanged(toOrientation);
|
||||
if (completion) completion();
|
||||
}];
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window {
|
||||
if (window == self.window) {
|
||||
return 1 << self.currentOrientation;
|
||||
}
|
||||
return UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
|
||||
- (CGAffineTransform)getRotationTransform:(UIInterfaceOrientation)orientation {
|
||||
CGAffineTransform rotationTransform = CGAffineTransformIdentity;
|
||||
if (orientation == UIInterfaceOrientationLandscapeLeft) {
|
||||
rotationTransform = CGAffineTransformMakeRotation(-M_PI_2);
|
||||
} else if (orientation == UIInterfaceOrientationLandscapeRight) {
|
||||
rotationTransform = CGAffineTransformMakeRotation(M_PI_2);
|
||||
}
|
||||
return rotationTransform;
|
||||
}
|
||||
|
||||
@end
|
||||
51
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeViewController.h
generated
Normal file
@@ -0,0 +1,51 @@
|
||||
//
|
||||
// ZFFullscreenViewController.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@class ZFLandscapeViewController;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol ZFLandscapeViewControllerDelegate <NSObject>
|
||||
@optional
|
||||
- (BOOL)ls_shouldAutorotate;
|
||||
- (void)rotationFullscreenViewController:(ZFLandscapeViewController *)viewController viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator;
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFLandscapeViewController : UIViewController
|
||||
|
||||
@property (nonatomic, weak, nullable) id<ZFLandscapeViewControllerDelegate> delegate;
|
||||
|
||||
@property (nonatomic, assign) BOOL disableAnimations;
|
||||
|
||||
@property (nonatomic, assign) BOOL statusBarHidden;
|
||||
/// default is UIStatusBarStyleLightContent.
|
||||
@property (nonatomic, assign) UIStatusBarStyle statusBarStyle;
|
||||
/// defalut is UIStatusBarAnimationSlide.
|
||||
@property (nonatomic, assign) UIStatusBarAnimation statusBarAnimation;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
69
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeViewController.m
generated
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// ZFFullScreenViewController.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// ZFFullscreenViewController.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLandscapeViewController.h"
|
||||
|
||||
@implementation ZFLandscapeViewController
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_statusBarStyle = UIStatusBarStyleLightContent;
|
||||
_statusBarAnimation = UIStatusBarAnimationSlide;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
|
||||
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
if ([self.delegate respondsToSelector:@selector(rotationFullscreenViewController:viewWillTransitionToSize:withTransitionCoordinator:)]) {
|
||||
[self.delegate rotationFullscreenViewController:self viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
|
||||
}
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return UIInterfaceOrientationMaskAllButUpsideDown;
|
||||
}
|
||||
|
||||
- (BOOL)prefersHomeIndicatorAutoHidden {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)prefersStatusBarHidden {
|
||||
return self.statusBarHidden;
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle {
|
||||
return self.statusBarStyle;
|
||||
}
|
||||
|
||||
- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
|
||||
return self.statusBarAnimation;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
35
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeViewController_iOS15.h
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// ZFLandscapeViewController_iOS15.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLandscapeViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ZFLandscapeViewController_iOS15 : ZFLandscapeViewController
|
||||
|
||||
@property (nonatomic, strong, readonly) UIView *playerSuperview;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
48
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeViewController_iOS15.m
generated
Normal file
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// ZFLandscapeViewController_iOS15.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLandscapeViewController_iOS15.h"
|
||||
|
||||
@implementation ZFLandscapeViewController_iOS15
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
_playerSuperview = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
_playerSuperview.backgroundColor = [UIColor clearColor];
|
||||
[self.view addSubview:_playerSuperview];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotate {
|
||||
return [self.delegate ls_shouldAutorotate];
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return UIInterfaceOrientationMaskAllButUpsideDown;
|
||||
}
|
||||
|
||||
- (BOOL)prefersHomeIndicatorAutoHidden {
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
37
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeWindow.h
generated
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// ZFLandScaprWindow.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ZFLandscapeViewController.h"
|
||||
@class ZFLandscapeRotationManager;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ZFLandscapeWindow : UIWindow
|
||||
|
||||
@property (nonatomic, weak) ZFLandscapeRotationManager *rotationManager;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
79
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFLandscapeWindow.m
generated
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// ZFLandScaprWindow.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFLandscapeWindow.h"
|
||||
#import "ZFLandscapeRotationManager_iOS15.h"
|
||||
|
||||
@implementation ZFLandscapeWindow
|
||||
@dynamic rootViewController;
|
||||
|
||||
- (void)setBackgroundColor:(nullable UIColor *)backgroundColor {}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
self.windowLevel = UIWindowLevelStatusBar - 1;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
if (self.windowScene == nil) {
|
||||
self.windowScene = UIApplication.sharedApplication.keyWindow.windowScene;
|
||||
}
|
||||
if (@available(iOS 9.0, *)) {
|
||||
[self.rootViewController loadViewIfNeeded];
|
||||
} else {
|
||||
[self.rootViewController view];
|
||||
}
|
||||
}
|
||||
self.hidden = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *_Nullable)event {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
static CGRect bounds;
|
||||
if (!CGRectEqualToRect(bounds, self.bounds)) {
|
||||
UIView *superview = self;
|
||||
if (@available(iOS 13.0, *)) {
|
||||
superview = self.subviews.firstObject;
|
||||
}
|
||||
[UIView performWithoutAnimation:^{
|
||||
for (UIView *view in superview.subviews) {
|
||||
if (view != self.rootViewController.view && [view isMemberOfClass:UIView.class]) {
|
||||
view.backgroundColor = UIColor.clearColor;
|
||||
for (UIView *subview in view.subviews) {
|
||||
subview.backgroundColor = UIColor.clearColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
bounds = self.bounds;
|
||||
self.rootViewController.view.frame = bounds;
|
||||
}
|
||||
|
||||
@end
|
||||
166
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFOrientationObserver.h
generated
Executable file
@@ -0,0 +1,166 @@
|
||||
//
|
||||
// ZFOrentationObserver.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ZFPlayerView.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// Full screen mode
|
||||
typedef NS_ENUM(NSUInteger, ZFFullScreenMode) {
|
||||
ZFFullScreenModeAutomatic, // Determine full screen mode automatically
|
||||
ZFFullScreenModeLandscape, // Landscape full screen mode
|
||||
ZFFullScreenModePortrait // Portrait full screen Model
|
||||
};
|
||||
|
||||
/// Portrait full screen mode.
|
||||
typedef NS_ENUM(NSUInteger, ZFPortraitFullScreenMode) {
|
||||
ZFPortraitFullScreenModeScaleToFill, // Full fill
|
||||
ZFPortraitFullScreenModeScaleAspectFit // contents scaled to fit with fixed aspect. remainder is transparent
|
||||
};
|
||||
|
||||
/// Player view mode
|
||||
typedef NS_ENUM(NSUInteger, ZFRotateType) {
|
||||
ZFRotateTypeNormal, // Normal
|
||||
ZFRotateTypeCell // Cell
|
||||
};
|
||||
|
||||
/**
|
||||
Rotation of support direction
|
||||
*/
|
||||
typedef NS_OPTIONS(NSUInteger, ZFInterfaceOrientationMask) {
|
||||
ZFInterfaceOrientationMaskUnknow = 0,
|
||||
ZFInterfaceOrientationMaskPortrait = (1 << 0),
|
||||
ZFInterfaceOrientationMaskLandscapeLeft = (1 << 1),
|
||||
ZFInterfaceOrientationMaskLandscapeRight = (1 << 2),
|
||||
ZFInterfaceOrientationMaskPortraitUpsideDown = (1 << 3),
|
||||
ZFInterfaceOrientationMaskLandscape = (ZFInterfaceOrientationMaskLandscapeLeft | ZFInterfaceOrientationMaskLandscapeRight),
|
||||
ZFInterfaceOrientationMaskAll = (ZFInterfaceOrientationMaskPortrait | ZFInterfaceOrientationMaskLandscape | ZFInterfaceOrientationMaskPortraitUpsideDown),
|
||||
ZFInterfaceOrientationMaskAllButUpsideDown = (ZFInterfaceOrientationMaskPortrait | ZFInterfaceOrientationMaskLandscape),
|
||||
};
|
||||
|
||||
/// This enumeration lists some of the gesture types that the player has by default.
|
||||
typedef NS_OPTIONS(NSUInteger, ZFDisablePortraitGestureTypes) {
|
||||
ZFDisablePortraitGestureTypesNone = 0,
|
||||
ZFDisablePortraitGestureTypesTap = 1 << 0,
|
||||
ZFDisablePortraitGestureTypesPan = 1 << 1,
|
||||
ZFDisablePortraitGestureTypesAll = (ZFDisablePortraitGestureTypesTap | ZFDisablePortraitGestureTypesPan)
|
||||
};
|
||||
|
||||
@protocol ZFPortraitOrientationDelegate <NSObject>
|
||||
|
||||
- (void)zf_orientationWillChange:(BOOL)isFullScreen;
|
||||
|
||||
- (void)zf_orientationDidChanged:(BOOL)isFullScreen;
|
||||
|
||||
- (void)zf_interationState:(BOOL)isDragging;
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFOrientationObserver : NSObject
|
||||
|
||||
/// update the rotateView and containerView.
|
||||
- (void)updateRotateView:(ZFPlayerView *)rotateView
|
||||
containerView:(UIView *)containerView;
|
||||
|
||||
/// Container view of a full screen state player.
|
||||
@property (nonatomic, strong, readonly, nullable) UIView *fullScreenContainerView;
|
||||
|
||||
/// Container view of a small screen state player.
|
||||
@property (nonatomic, weak) UIView *containerView;
|
||||
|
||||
/// The block invoked When player will rotate.
|
||||
@property (nonatomic, copy, nullable) void(^orientationWillChange)(ZFOrientationObserver *observer, BOOL isFullScreen);
|
||||
|
||||
/// The block invoked when player rotated.
|
||||
@property (nonatomic, copy, nullable) void(^orientationDidChanged)(ZFOrientationObserver *observer, BOOL isFullScreen);
|
||||
|
||||
/// Full screen mode, the default landscape into full screen
|
||||
@property (nonatomic) ZFFullScreenMode fullScreenMode;
|
||||
|
||||
@property (nonatomic, assign) ZFPortraitFullScreenMode portraitFullScreenMode;
|
||||
|
||||
/// rotate duration, default is 0.30
|
||||
@property (nonatomic) NSTimeInterval duration;
|
||||
|
||||
/// If the full screen.
|
||||
@property (nonatomic, readonly, getter=isFullScreen) BOOL fullScreen;
|
||||
|
||||
/// Lock screen orientation
|
||||
@property (nonatomic, getter=isLockedScreen) BOOL lockedScreen;
|
||||
|
||||
/// The fullscreen statusbar hidden.
|
||||
@property (nonatomic, assign) BOOL fullScreenStatusBarHidden;
|
||||
|
||||
/// default is UIStatusBarStyleLightContent.
|
||||
@property (nonatomic, assign) UIStatusBarStyle fullScreenStatusBarStyle;
|
||||
|
||||
/// defalut is UIStatusBarAnimationSlide.
|
||||
@property (nonatomic, assign) UIStatusBarAnimation fullScreenStatusBarAnimation;
|
||||
|
||||
@property (nonatomic, assign) CGSize presentationSize;
|
||||
|
||||
/// default is ZFDisablePortraitGestureTypesAll.
|
||||
@property (nonatomic, assign) ZFDisablePortraitGestureTypes disablePortraitGestureTypes;
|
||||
|
||||
/// The current orientation of the player.
|
||||
/// Default is UIInterfaceOrientationPortrait.
|
||||
@property (nonatomic, readonly) UIInterfaceOrientation currentOrientation;
|
||||
|
||||
/// Whether allow the video orientation rotate.
|
||||
/// default is YES.
|
||||
@property (nonatomic, assign) BOOL allowOrientationRotation;
|
||||
|
||||
/// The support Interface Orientation,default is ZFInterfaceOrientationMaskAllButUpsideDown
|
||||
@property (nonatomic, assign) ZFInterfaceOrientationMask supportInterfaceOrientation;
|
||||
|
||||
/// Add the device orientation observer.
|
||||
- (void)addDeviceOrientationObserver;
|
||||
|
||||
/// Remove the device orientation observer.
|
||||
- (void)removeDeviceOrientationObserver;
|
||||
|
||||
/// Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModeLandscape.
|
||||
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated;
|
||||
|
||||
/// Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModeLandscape.
|
||||
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated completion:(void(^ __nullable)(void))completion;
|
||||
|
||||
/// Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModePortrait.
|
||||
- (void)enterPortraitFullScreen:(BOOL)fullScreen animated:(BOOL)animated;
|
||||
|
||||
/// Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModePortrait.
|
||||
- (void)enterPortraitFullScreen:(BOOL)fullScreen animated:(BOOL)animated completion:(void(^ __nullable)(void))completion;
|
||||
|
||||
/// FullScreen mode is determined by ZFFullScreenMode.
|
||||
- (void)enterFullScreen:(BOOL)fullScreen animated:(BOOL)animated;
|
||||
|
||||
/// FullScreen mode is determined by ZFFullScreenMode.
|
||||
- (void)enterFullScreen:(BOOL)fullScreen animated:(BOOL)animated completion:(void (^ _Nullable)(void))completion;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
|
||||
362
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFOrientationObserver.m
generated
Executable file
@@ -0,0 +1,362 @@
|
||||
|
||||
// ZFOrentationObserver.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFOrientationObserver.h"
|
||||
#import "ZFLandscapeWindow.h"
|
||||
#import "ZFPortraitViewController.h"
|
||||
#import "ZFPlayerConst.h"
|
||||
#import <objc/runtime.h>
|
||||
#import "ZFLandscapeRotationManager_iOS15.h"
|
||||
#import "ZFLandscapeRotationManager_iOS16.h"
|
||||
|
||||
@interface UIWindow (CurrentViewController)
|
||||
|
||||
/*!
|
||||
@method currentViewController
|
||||
@return Returns the topViewController in stack of topMostController.
|
||||
*/
|
||||
+ (UIViewController*)zf_currentViewController;
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIWindow (CurrentViewController)
|
||||
|
||||
+ (UIViewController*)zf_currentViewController {
|
||||
__block UIWindow *window;
|
||||
if (@available(iOS 13, *)) {
|
||||
[[UIApplication sharedApplication].connectedScenes enumerateObjectsUsingBlock:^(UIScene * _Nonnull scene, BOOL * _Nonnull scenesStop) {
|
||||
if ([scene isKindOfClass: [UIWindowScene class]]) {
|
||||
UIWindowScene * windowScene = (UIWindowScene *)scene;
|
||||
[windowScene.windows enumerateObjectsUsingBlock:^(UIWindow * _Nonnull windowTemp, NSUInteger idx, BOOL * _Nonnull windowStop) {
|
||||
if (windowTemp.isKeyWindow) {
|
||||
window = windowTemp;
|
||||
*windowStop = YES;
|
||||
*scenesStop = YES;
|
||||
}
|
||||
}];
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
window = [[UIApplication sharedApplication].delegate window];
|
||||
}
|
||||
UIViewController *topViewController = [window rootViewController];
|
||||
while (true) {
|
||||
if (topViewController.presentedViewController) {
|
||||
topViewController = topViewController.presentedViewController;
|
||||
} else if ([topViewController isKindOfClass:[UINavigationController class]] && [(UINavigationController *)topViewController topViewController]) {
|
||||
topViewController = [(UINavigationController *)topViewController topViewController];
|
||||
} else if ([topViewController isKindOfClass:[UITabBarController class]]) {
|
||||
UITabBarController *tab = (UITabBarController *)topViewController;
|
||||
topViewController = tab.selectedViewController;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return topViewController;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFOrientationObserver ()
|
||||
|
||||
@property (nonatomic, weak) ZFPlayerView *view;
|
||||
|
||||
@property (nonatomic, assign, getter=isFullScreen) BOOL fullScreen;
|
||||
|
||||
@property (nonatomic, strong) ZFPortraitViewController *portraitViewController;
|
||||
|
||||
@property (nonatomic, strong) ZFLandscapeRotationManager *landscapeRotationManager;
|
||||
|
||||
/// current device orientation observer is activie.
|
||||
@property (nonatomic, assign) BOOL activeDeviceObserver;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFOrientationObserver
|
||||
@synthesize presentationSize = _presentationSize;
|
||||
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_duration = 0.30;
|
||||
_fullScreenMode = ZFFullScreenModeLandscape;
|
||||
_portraitFullScreenMode = ZFPortraitFullScreenModeScaleToFill;
|
||||
_disablePortraitGestureTypes = ZFDisablePortraitGestureTypesAll;
|
||||
self.supportInterfaceOrientation = ZFInterfaceOrientationMaskAllButUpsideDown;
|
||||
self.allowOrientationRotation = YES;
|
||||
self.activeDeviceObserver = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)updateRotateView:(ZFPlayerView *)rotateView
|
||||
containerView:(UIView *)containerView {
|
||||
self.view = rotateView;
|
||||
self.containerView = containerView;
|
||||
[self.landscapeRotationManager updateRotateView:rotateView containerView:containerView];
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
[self removeDeviceOrientationObserver];
|
||||
}
|
||||
|
||||
- (void)addDeviceOrientationObserver {
|
||||
if (self.allowOrientationRotation) {
|
||||
self.activeDeviceObserver = YES;
|
||||
if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {
|
||||
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDeviceOrientationChange) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeDeviceOrientationObserver {
|
||||
self.activeDeviceObserver = NO;
|
||||
if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {
|
||||
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
}
|
||||
|
||||
- (void)handleDeviceOrientationChange {
|
||||
if (self.fullScreenMode == ZFFullScreenModePortrait || !self.allowOrientationRotation) return;
|
||||
[self.landscapeRotationManager handleDeviceOrientationChange];
|
||||
}
|
||||
|
||||
#pragma mark - public
|
||||
|
||||
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated {
|
||||
[self rotateToOrientation:orientation animated:animated completion:nil];
|
||||
}
|
||||
|
||||
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated completion:(void(^ __nullable)(void))completion {
|
||||
if (self.fullScreenMode == ZFFullScreenModePortrait) return;
|
||||
[self.landscapeRotationManager rotateToOrientation:orientation animated:animated completion:completion];
|
||||
}
|
||||
|
||||
- (void)enterPortraitFullScreen:(BOOL)fullScreen animated:(BOOL)animated {
|
||||
[self enterPortraitFullScreen:fullScreen animated:animated completion:nil];
|
||||
}
|
||||
|
||||
- (void)enterPortraitFullScreen:(BOOL)fullScreen animated:(BOOL)animated completion:(void(^ __nullable)(void))completion {
|
||||
self.fullScreen = fullScreen;
|
||||
if (fullScreen) {
|
||||
self.portraitViewController.contentView = self.view;
|
||||
self.portraitViewController.containerView = self.containerView;
|
||||
self.portraitViewController.duration = self.duration;
|
||||
if (self.portraitFullScreenMode == ZFPortraitFullScreenModeScaleAspectFit) {
|
||||
self.portraitViewController.presentationSize = self.presentationSize;
|
||||
} else if (self.portraitFullScreenMode == ZFPortraitFullScreenModeScaleToFill) {
|
||||
self.portraitViewController.presentationSize = CGSizeMake(ZFPlayerScreenWidth, ZFPlayerScreenHeight);
|
||||
}
|
||||
self.portraitViewController.fullScreenAnimation = animated;
|
||||
[[UIWindow zf_currentViewController] presentViewController:self.portraitViewController animated:animated completion:^{
|
||||
if (completion) completion();
|
||||
}];
|
||||
} else {
|
||||
self.portraitViewController.fullScreenAnimation = animated;
|
||||
[self.portraitViewController dismissViewControllerAnimated:animated completion:^{
|
||||
if (completion) completion();
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)enterFullScreen:(BOOL)fullScreen animated:(BOOL)animated {
|
||||
[self enterFullScreen:fullScreen animated:animated completion:nil];
|
||||
}
|
||||
|
||||
- (void)enterFullScreen:(BOOL)fullScreen animated:(BOOL)animated completion:(void (^ _Nullable)(void))completion {
|
||||
if (self.fullScreenMode == ZFFullScreenModePortrait) {
|
||||
[self enterPortraitFullScreen:fullScreen animated:animated completion:completion];
|
||||
} else {
|
||||
UIInterfaceOrientation orientation = UIInterfaceOrientationUnknown;
|
||||
orientation = fullScreen? UIInterfaceOrientationLandscapeRight : UIInterfaceOrientationPortrait;
|
||||
[self rotateToOrientation:orientation animated:animated completion:completion];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (ZFPortraitViewController *)portraitViewController {
|
||||
if (!_portraitViewController) {
|
||||
@zf_weakify(self)
|
||||
_portraitViewController = [[ZFPortraitViewController alloc] init];
|
||||
if (@available(iOS 9.0, *)) {
|
||||
[_portraitViewController loadViewIfNeeded];
|
||||
} else {
|
||||
[_portraitViewController view];
|
||||
}
|
||||
_portraitViewController.orientationWillChange = ^(BOOL isFullScreen) {
|
||||
@zf_strongify(self)
|
||||
self.fullScreen = isFullScreen;
|
||||
if (self.orientationWillChange) self.orientationWillChange(self, isFullScreen);
|
||||
};
|
||||
_portraitViewController.orientationDidChanged = ^(BOOL isFullScreen) {
|
||||
@zf_strongify(self)
|
||||
self.fullScreen = isFullScreen;
|
||||
if (self.orientationDidChanged) self.orientationDidChanged(self, isFullScreen);
|
||||
};
|
||||
}
|
||||
return _portraitViewController;
|
||||
}
|
||||
|
||||
- (ZFLandscapeRotationManager *)landscapeRotationManager {
|
||||
if (!_landscapeRotationManager) {
|
||||
if (@available(iOS 16.0, *)) {
|
||||
_landscapeRotationManager = [[ZFLandscapeRotationManager_iOS16 alloc] init];
|
||||
} else {
|
||||
_landscapeRotationManager = [[ZFLandscapeRotationManager_iOS15 alloc] init];
|
||||
}
|
||||
@zf_weakify(self)
|
||||
_landscapeRotationManager.orientationWillChange = ^(UIInterfaceOrientation orientation) {
|
||||
@zf_strongify(self)
|
||||
self.fullScreen = UIInterfaceOrientationIsLandscape(orientation);
|
||||
if (self.orientationWillChange) self.orientationWillChange(self, self.fullScreen);
|
||||
};
|
||||
|
||||
_landscapeRotationManager.orientationDidChanged = ^(UIInterfaceOrientation orientation) {
|
||||
@zf_strongify(self)
|
||||
self.fullScreen = UIInterfaceOrientationIsLandscape(orientation);
|
||||
if (self.orientationDidChanged) self.orientationDidChanged(self, self.fullScreen);
|
||||
};
|
||||
}
|
||||
return _landscapeRotationManager;
|
||||
}
|
||||
|
||||
- (UIView *)fullScreenContainerView {
|
||||
if (self.fullScreenMode == ZFFullScreenModeLandscape) {
|
||||
return self.landscapeRotationManager.landscapeViewController.view;
|
||||
} else if (self.fullScreenMode == ZFFullScreenModePortrait) {
|
||||
return self.portraitViewController.view;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UIInterfaceOrientation)currentOrientation {
|
||||
if (self.fullScreenMode == ZFFullScreenModeLandscape) {
|
||||
return self.landscapeRotationManager.currentOrientation;
|
||||
}
|
||||
return [self.landscapeRotationManager getCurrentOrientation];
|
||||
}
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (void)setLockedScreen:(BOOL)lockedScreen {
|
||||
_lockedScreen = lockedScreen;
|
||||
self.landscapeRotationManager.lockedScreen = lockedScreen;
|
||||
if (lockedScreen) {
|
||||
[self removeDeviceOrientationObserver];
|
||||
} else {
|
||||
[self addDeviceOrientationObserver];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFullScreen:(BOOL)fullScreen {
|
||||
_fullScreen = fullScreen;
|
||||
[self.landscapeRotationManager.landscapeViewController setNeedsStatusBarAppearanceUpdate];
|
||||
[UIViewController attemptRotationToDeviceOrientation];
|
||||
}
|
||||
|
||||
- (void)setFullScreenStatusBarHidden:(BOOL)fullScreenStatusBarHidden {
|
||||
_fullScreenStatusBarHidden = fullScreenStatusBarHidden;
|
||||
if (self.fullScreenMode == ZFFullScreenModePortrait) {
|
||||
self.portraitViewController.statusBarHidden = fullScreenStatusBarHidden;
|
||||
[self.portraitViewController setNeedsStatusBarAppearanceUpdate];
|
||||
} else if (self.fullScreenMode == ZFFullScreenModeLandscape) {
|
||||
self.landscapeRotationManager.landscapeViewController.statusBarHidden = fullScreenStatusBarHidden;
|
||||
[self.landscapeRotationManager.landscapeViewController setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFullScreenStatusBarStyle:(UIStatusBarStyle)fullScreenStatusBarStyle {
|
||||
_fullScreenStatusBarStyle = fullScreenStatusBarStyle;
|
||||
if (self.fullScreenMode == ZFFullScreenModePortrait) {
|
||||
self.portraitViewController.statusBarStyle = fullScreenStatusBarStyle;
|
||||
[self.portraitViewController setNeedsStatusBarAppearanceUpdate];
|
||||
} else if (self.fullScreenMode == ZFFullScreenModeLandscape) {
|
||||
self.landscapeRotationManager.landscapeViewController.statusBarStyle = fullScreenStatusBarStyle;
|
||||
[self.landscapeRotationManager.landscapeViewController setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setFullScreenStatusBarAnimation:(UIStatusBarAnimation)fullScreenStatusBarAnimation {
|
||||
_fullScreenStatusBarAnimation = fullScreenStatusBarAnimation;
|
||||
if (self.fullScreenMode == ZFFullScreenModePortrait) {
|
||||
self.portraitViewController.statusBarAnimation = fullScreenStatusBarAnimation;
|
||||
[self.portraitViewController setNeedsStatusBarAppearanceUpdate];
|
||||
} else if (self.fullScreenMode == ZFFullScreenModeLandscape) {
|
||||
self.landscapeRotationManager.landscapeViewController.statusBarAnimation = fullScreenStatusBarAnimation;
|
||||
[self.landscapeRotationManager.landscapeViewController setNeedsStatusBarAppearanceUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDisablePortraitGestureTypes:(ZFDisablePortraitGestureTypes)disablePortraitGestureTypes {
|
||||
_disablePortraitGestureTypes = disablePortraitGestureTypes;
|
||||
self.portraitViewController.disablePortraitGestureTypes = disablePortraitGestureTypes;
|
||||
}
|
||||
|
||||
- (void)setPresentationSize:(CGSize)presentationSize {
|
||||
_presentationSize = presentationSize;
|
||||
if (self.fullScreenMode == ZFFullScreenModePortrait && self.portraitFullScreenMode == ZFPortraitFullScreenModeScaleAspectFit) {
|
||||
self.portraitViewController.presentationSize = presentationSize;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setView:(ZFPlayerView *)view {
|
||||
if (view == _view) { return; }
|
||||
_view = view;
|
||||
if (self.fullScreenMode == ZFFullScreenModeLandscape) {
|
||||
self.landscapeRotationManager.contentView = view;
|
||||
} else if (self.fullScreenMode == ZFFullScreenModePortrait) {
|
||||
self.portraitViewController.contentView = view;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setContainerView:(UIView *)containerView {
|
||||
if (containerView == _containerView) { return; }
|
||||
_containerView = containerView;
|
||||
if (self.fullScreenMode == ZFFullScreenModeLandscape) {
|
||||
self.landscapeRotationManager.containerView = containerView;
|
||||
} else if (self.fullScreenMode == ZFFullScreenModePortrait) {
|
||||
self.portraitViewController.containerView = containerView;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setAllowOrientationRotation:(BOOL)allowOrientationRotation {
|
||||
_allowOrientationRotation = allowOrientationRotation;
|
||||
self.landscapeRotationManager.allowOrientationRotation = allowOrientationRotation;
|
||||
}
|
||||
|
||||
- (void)setSupportInterfaceOrientation:(ZFInterfaceOrientationMask)supportInterfaceOrientation {
|
||||
_supportInterfaceOrientation = supportInterfaceOrientation;
|
||||
self.landscapeRotationManager.supportInterfaceOrientation = supportInterfaceOrientation;
|
||||
}
|
||||
|
||||
- (void)setActiveDeviceObserver:(BOOL)activeDeviceObserver {
|
||||
_activeDeviceObserver = activeDeviceObserver;
|
||||
self.landscapeRotationManager.activeDeviceObserver = activeDeviceObserver;
|
||||
}
|
||||
|
||||
@end
|
||||
47
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFPersentInteractiveTransition.h
generated
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// ZFPersentInteractiveTransition.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ZFOrientationObserver.h"
|
||||
|
||||
@interface ZFPersentInteractiveTransition : UIPercentDrivenInteractiveTransition
|
||||
|
||||
@property (nonatomic, weak) id<ZFPortraitOrientationDelegate> delagate;
|
||||
|
||||
@property (nonatomic, assign) BOOL interation;
|
||||
|
||||
/// default is ZFDisablePortraitGestureTypesNone.
|
||||
@property (nonatomic, assign) ZFDisablePortraitGestureTypes disablePortraitGestureTypes;
|
||||
|
||||
@property (nonatomic, assign) BOOL fullScreenAnimation;
|
||||
|
||||
@property (nonatomic, assign) CGRect contentFullScreenRect;
|
||||
|
||||
@property (nonatomic, weak) UIViewController *viewController;
|
||||
|
||||
- (void)updateContentView:(UIView *)contenView
|
||||
containerView:(UIView *)containerView;
|
||||
|
||||
@end
|
||||
296
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFPersentInteractiveTransition.m
generated
Normal file
@@ -0,0 +1,296 @@
|
||||
//
|
||||
// ZFPersentInteractiveTransition.m
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2020年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import "ZFPersentInteractiveTransition.h"
|
||||
|
||||
@interface ZFPersentInteractiveTransition () <UIGestureRecognizerDelegate>
|
||||
|
||||
@property (nonatomic, weak) id<UIViewControllerContextTransitioning> transitionContext;
|
||||
@property (nonatomic, strong) UIView *bgView;
|
||||
@property (nonatomic, assign) CGPoint transitionImgViewCenter;
|
||||
@property (nonatomic, strong) UIView *contentView;
|
||||
@property (nonatomic, strong) UIView *containerView;
|
||||
@property (nonatomic, assign) CGFloat scrollViewZoomScale;
|
||||
@property (nonatomic, assign) CGSize scrollViewContentSize;
|
||||
@property (nonatomic, assign) CGPoint scrollViewContentOffset;
|
||||
@property (nonatomic, strong) UIPanGestureRecognizer *panGesture;
|
||||
@property (nonatomic, strong) UITapGestureRecognizer *tapGesture;
|
||||
@property (nonatomic, assign) BOOL isDragging;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ZFPersentInteractiveTransition
|
||||
|
||||
- (void)updateContentView:(UIView *)contenView
|
||||
containerView:(UIView *)containerView {
|
||||
self.contentView = contenView;
|
||||
self.containerView = containerView;
|
||||
}
|
||||
|
||||
- (void)removeGestureToView:(UIView *)view {
|
||||
[view removeGestureRecognizer:self.tapGesture];
|
||||
[view removeGestureRecognizer:self.panGesture];
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
|
||||
if ([otherGestureRecognizer.view isKindOfClass:[UICollectionView class]]) {
|
||||
return NO;
|
||||
}
|
||||
if ([otherGestureRecognizer.view isKindOfClass:[UIScrollView class]]) {
|
||||
UIScrollView *scrollView = (UIScrollView *)otherGestureRecognizer.view;
|
||||
if (scrollView.contentOffset.y <= 0 && !scrollView.zooming) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
if ([otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]] || [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
|
||||
ZFDisablePortraitGestureTypes type = ZFDisablePortraitGestureTypesNone;
|
||||
if (gestureRecognizer == self.tapGesture) type = ZFDisablePortraitGestureTypesTap;
|
||||
else if (gestureRecognizer == self.panGesture) type = ZFDisablePortraitGestureTypesPan;
|
||||
else return NO;
|
||||
|
||||
switch (type) {
|
||||
case ZFDisablePortraitGestureTypesTap: {
|
||||
if (self.disablePortraitGestureTypes & ZFDisablePortraitGestureTypesTap) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ZFDisablePortraitGestureTypesPan: {
|
||||
if (self.disablePortraitGestureTypes & ZFDisablePortraitGestureTypesPan) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)tapGestureAction {
|
||||
[self.viewController dismissViewControllerAnimated:self.fullScreenAnimation completion:nil];
|
||||
}
|
||||
|
||||
- (void)gestureRecognizeDidUpdate:(UIPanGestureRecognizer *)gestureRecognizer {
|
||||
CGFloat scale = 0;
|
||||
CGPoint translation = [gestureRecognizer translationInView:gestureRecognizer.view];
|
||||
scale = translation.y / ((gestureRecognizer.view.frame.size.height - 50) / 2);
|
||||
|
||||
if (scale > 1.f) {
|
||||
scale = 1.f;
|
||||
}
|
||||
switch (gestureRecognizer.state) {
|
||||
case UIGestureRecognizerStateBegan: {
|
||||
if (scale < 0) return;
|
||||
self.interation = YES;
|
||||
[self.viewController dismissViewControllerAnimated:self.fullScreenAnimation completion:nil];
|
||||
}
|
||||
break;
|
||||
case UIGestureRecognizerStateChanged: {
|
||||
if (self.interation) {
|
||||
if (scale < 0.f) {
|
||||
scale = 0.f;
|
||||
}
|
||||
CGFloat imageViewScale = 1 - scale * 0.5;
|
||||
if (imageViewScale < 0.4) {
|
||||
imageViewScale = 0.4;
|
||||
}
|
||||
self.contentView.center = CGPointMake(self.transitionImgViewCenter.x + translation.x, self.transitionImgViewCenter.y + translation.y);
|
||||
self.contentView.transform = CGAffineTransformMakeScale(imageViewScale, imageViewScale);
|
||||
[self updateInterPercent:imageViewScale];
|
||||
[self updateInteractiveTransition:scale];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case UIGestureRecognizerStateEnded: {
|
||||
if (self.interation) {
|
||||
if (scale < 0.f) {
|
||||
scale = 0.f;
|
||||
}
|
||||
self.interation = NO;
|
||||
if (scale < 0.15f) {
|
||||
[self cancelInteractiveTransition];
|
||||
[self interPercentCancel];
|
||||
} else {
|
||||
[self finishInteractiveTransition];
|
||||
[self interPercentFinish];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
if (self.interation) {
|
||||
self.interation = NO;
|
||||
[self cancelInteractiveTransition];
|
||||
[self interPercentCancel];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)beginInterPercent {
|
||||
id<UIViewControllerContextTransitioning> transitionContext = self.transitionContext;
|
||||
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
|
||||
UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
|
||||
if ([toVC isKindOfClass:[UINavigationController class]]) {
|
||||
UINavigationController *nav = (UINavigationController *)toVC;
|
||||
toVC = nav.viewControllers.lastObject;
|
||||
} else if ([toVC isKindOfClass:[UITabBarController class]]) {
|
||||
UITabBarController *tabBar = (UITabBarController *)toVC;
|
||||
if ([tabBar.selectedViewController isKindOfClass:[UINavigationController class]]) {
|
||||
UINavigationController *nav = (UINavigationController *)tabBar.selectedViewController;
|
||||
toVC = nav.viewControllers.lastObject;
|
||||
} else {
|
||||
toVC = tabBar.selectedViewController;
|
||||
}
|
||||
}
|
||||
|
||||
UIView *containerView = [transitionContext containerView];
|
||||
CGRect tempImageViewFrame = [fromVC.view convertRect:self.contentView.frame toView:toVC.view];
|
||||
|
||||
self.bgView = [[UIView alloc] initWithFrame:containerView.bounds];
|
||||
self.contentView.frame = tempImageViewFrame;
|
||||
self.transitionImgViewCenter = self.contentView.center;
|
||||
|
||||
[containerView addSubview:self.bgView];
|
||||
[containerView addSubview:self.contentView];
|
||||
[containerView addSubview:fromVC.view];
|
||||
|
||||
self.bgView.backgroundColor = [UIColor blackColor];
|
||||
fromVC.view.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
|
||||
- (void)updateInterPercent:(CGFloat)scale {
|
||||
UIViewController *fromVC = [self.transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
|
||||
fromVC.view.alpha = scale;
|
||||
self.bgView.alpha = scale;
|
||||
}
|
||||
|
||||
- (void)interPercentCancel {
|
||||
id<UIViewControllerContextTransitioning> transitionContext = self.transitionContext;
|
||||
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
|
||||
[UIView animateWithDuration:0.2f animations:^{
|
||||
fromVC.view.alpha = 1;
|
||||
self.contentView.transform = CGAffineTransformIdentity;
|
||||
self.contentView.center = self.transitionImgViewCenter;
|
||||
self.bgView.alpha = 1;
|
||||
} completion:^(BOOL finished) {
|
||||
fromVC.view.backgroundColor = [UIColor blackColor];
|
||||
self.contentView.layer.anchorPoint = CGPointMake(0.5f, 0.5f);
|
||||
self.contentView.frame = self.contentFullScreenRect;
|
||||
if (self.scrollViewContentOffset.y < 0) {
|
||||
self.scrollViewContentOffset = CGPointMake(self.scrollViewContentOffset.x, 0);
|
||||
}
|
||||
[self.viewController.view addSubview:self.contentView];
|
||||
[self.bgView removeFromSuperview];
|
||||
self.bgView = nil;
|
||||
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)interPercentFinish {
|
||||
id<UIViewControllerContextTransitioning> transitionContext = self.transitionContext;
|
||||
UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
|
||||
UIViewController *toVC = [self.transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
|
||||
if ([toVC isKindOfClass:[UINavigationController class]]) {
|
||||
UINavigationController *nav = (UINavigationController *)toVC;
|
||||
toVC = nav.viewControllers.lastObject;
|
||||
} else if ([toVC isKindOfClass:[UITabBarController class]]) {
|
||||
UITabBarController *tabBar = (UITabBarController *)toVC;
|
||||
if ([tabBar.selectedViewController isKindOfClass:[UINavigationController class]]) {
|
||||
UINavigationController *nav = (UINavigationController *)tabBar.selectedViewController;
|
||||
toVC = nav.viewControllers.lastObject;
|
||||
} else {
|
||||
toVC = tabBar.selectedViewController;
|
||||
}
|
||||
}
|
||||
CGRect tempImageViewFrame = self.contentView.frame;
|
||||
self.contentView.layer.anchorPoint = CGPointMake(0.5, 0.5);
|
||||
self.contentView.transform = CGAffineTransformIdentity;
|
||||
self.contentView.frame = tempImageViewFrame;
|
||||
|
||||
CGRect toRect = [self.containerView convertRect:self.containerView.bounds toView:self.containerView.window];
|
||||
[self.delagate zf_orientationWillChange:NO];
|
||||
[UIView animateWithDuration:0.3f animations:^{
|
||||
self.contentView.frame = toRect;
|
||||
fromVC.view.alpha = 0;
|
||||
self.bgView.alpha = 0;
|
||||
toVC.navigationController.navigationBar.alpha = 1;
|
||||
[self.contentView layoutIfNeeded];
|
||||
} completion:^(BOOL finished) {
|
||||
[self.containerView addSubview:self.contentView];
|
||||
self.contentView.frame = self.containerView.bounds;
|
||||
[self.contentView layoutIfNeeded];
|
||||
[self.bgView removeFromSuperview];
|
||||
fromVC.view.backgroundColor = [UIColor blackColor];
|
||||
[self.delagate zf_orientationDidChanged:NO];
|
||||
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)startInteractiveTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
|
||||
self.transitionContext = transitionContext;
|
||||
[self beginInterPercent];
|
||||
}
|
||||
|
||||
- (void)setInteration:(BOOL)interation {
|
||||
_interation = interation;
|
||||
if ([self.delagate respondsToSelector:@selector(zf_interationState:)]) {
|
||||
[self.delagate zf_interationState:interation];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setViewController:(UIViewController *)viewController {
|
||||
_viewController = viewController;
|
||||
[self removeGestureToView:viewController.view];
|
||||
[viewController.view addGestureRecognizer:self.panGesture];
|
||||
[viewController.view addGestureRecognizer:self.tapGesture];
|
||||
}
|
||||
|
||||
#pragma mark - getter
|
||||
|
||||
- (UIPanGestureRecognizer *)panGesture {
|
||||
if (!_panGesture) {
|
||||
_panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(gestureRecognizeDidUpdate:)];
|
||||
_panGesture.delegate = self;
|
||||
}
|
||||
return _panGesture;
|
||||
}
|
||||
|
||||
- (UITapGestureRecognizer *)tapGesture {
|
||||
if (!_tapGesture) {
|
||||
_tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureAction)];
|
||||
_tapGesture.delegate = self;
|
||||
}
|
||||
return _tapGesture;
|
||||
}
|
||||
|
||||
@end
|
||||
38
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFPlayer.h
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// ZFPlayer.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for ZFPlayer.
|
||||
FOUNDATION_EXPORT double ZFPlayerVersionNumber;
|
||||
|
||||
//! Project version string for ZFPlayer.
|
||||
FOUNDATION_EXPORT const unsigned char ZFPlayerVersionString[];
|
||||
|
||||
#import "ZFPlayerController.h"
|
||||
#import "ZFPlayerMediaControl.h"
|
||||
#import "ZFKVOController.h"
|
||||
#import "UIScrollView+ZFPlayer.h"
|
||||
#import "ZFPlayerLogManager.h"
|
||||
#import "ZFPlayerConst.h"
|
||||
130
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFPlayerConst.h
generated
Normal file
@@ -0,0 +1,130 @@
|
||||
//
|
||||
// ZFPlayerConst.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ZFPlayerPlaybackState) {
|
||||
ZFPlayerPlayStateUnknown,
|
||||
ZFPlayerPlayStatePlaying,
|
||||
ZFPlayerPlayStatePaused,
|
||||
ZFPlayerPlayStatePlayFailed,
|
||||
ZFPlayerPlayStatePlayStopped
|
||||
};
|
||||
|
||||
typedef NS_OPTIONS(NSUInteger, ZFPlayerLoadState) {
|
||||
ZFPlayerLoadStateUnknown = 0,
|
||||
ZFPlayerLoadStatePrepare = 1 << 0,
|
||||
ZFPlayerLoadStatePlayable = 1 << 1,
|
||||
ZFPlayerLoadStatePlaythroughOK = 1 << 2, // Playback will be automatically started.
|
||||
ZFPlayerLoadStateStalled = 1 << 3, // Playback will be automatically paused in this state, if started.
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, ZFPlayerScalingMode) {
|
||||
ZFPlayerScalingModeNone, // No scaling.
|
||||
ZFPlayerScalingModeAspectFit, // Uniform scale until one dimension fits.
|
||||
ZFPlayerScalingModeAspectFill, // Uniform scale until the movie fills the visible bounds. One dimension may have clipped contents.
|
||||
ZFPlayerScalingModeFill // Non-uniform scale. Both render dimensions will exactly match the visible bounds.
|
||||
};
|
||||
|
||||
/**
|
||||
Synthsize a weak or strong reference.
|
||||
|
||||
Example:
|
||||
@zf_weakify(self)
|
||||
[self doSomething^{
|
||||
@zf_strongify(self)
|
||||
if (!self) return;
|
||||
...
|
||||
}];
|
||||
|
||||
*/
|
||||
#ifndef weakify
|
||||
#if DEBUG
|
||||
#if __has_feature(objc_arc)
|
||||
#define zf_weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
|
||||
#else
|
||||
#define zf_weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
|
||||
#endif
|
||||
#else
|
||||
#if __has_feature(objc_arc)
|
||||
#define zf_weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
|
||||
#else
|
||||
#define zf_weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef strongify
|
||||
#if DEBUG
|
||||
#if __has_feature(objc_arc)
|
||||
#define zf_strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
|
||||
#else
|
||||
#define zf_strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
|
||||
#endif
|
||||
#else
|
||||
#if __has_feature(objc_arc)
|
||||
#define zf_strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
|
||||
#else
|
||||
#define zf_strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Screen width
|
||||
#define ZFPlayerScreenWidth [[UIScreen mainScreen] bounds].size.width
|
||||
// Screen height
|
||||
#define ZFPlayerScreenHeight [[UIScreen mainScreen] bounds].size.height
|
||||
|
||||
|
||||
// deprecated
|
||||
#ifndef weakify
|
||||
#if DEBUG
|
||||
#if __has_feature(objc_arc)
|
||||
#define weakify(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object;
|
||||
#else
|
||||
#define weakify(object) autoreleasepool{} __block __typeof__(object) block##_##object = object;
|
||||
#endif
|
||||
#else
|
||||
#if __has_feature(objc_arc)
|
||||
#define weakify(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object;
|
||||
#else
|
||||
#define weakify(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef strongify
|
||||
#if DEBUG
|
||||
#if __has_feature(objc_arc)
|
||||
#define strongify(object) autoreleasepool{} __typeof__(object) object = weak##_##object;
|
||||
#else
|
||||
#define strongify(object) autoreleasepool{} __typeof__(object) object = block##_##object;
|
||||
#endif
|
||||
#else
|
||||
#if __has_feature(objc_arc)
|
||||
#define strongify(object) try{} @finally{} __typeof__(object) object = weak##_##object;
|
||||
#else
|
||||
#define strongify(object) try{} @finally{} __typeof__(object) object = block##_##object;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
603
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFPlayerController.h
generated
Normal file
@@ -0,0 +1,603 @@
|
||||
//
|
||||
// ZFPlayerController.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "ZFPlayerMediaPlayback.h"
|
||||
#import "ZFOrientationObserver.h"
|
||||
#import "ZFPlayerMediaControl.h"
|
||||
#import "ZFPlayerGestureControl.h"
|
||||
#import "ZFPlayerNotification.h"
|
||||
#import "ZFFloatView.h"
|
||||
#import "UIScrollView+ZFPlayer.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ZFPlayerController : NSObject
|
||||
|
||||
/// The video contrainerView in normal model.
|
||||
@property (nonatomic, weak, nullable) UIView *containerView;
|
||||
|
||||
/// The currentPlayerManager must conform `ZFPlayerMediaPlayback` protocol.
|
||||
@property (nonatomic, strong) id<ZFPlayerMediaPlayback> currentPlayerManager;
|
||||
|
||||
/// The custom controlView must conform `ZFPlayerMediaControl` protocol.
|
||||
@property (nonatomic, strong, nullable) UIView<ZFPlayerMediaControl> *controlView;
|
||||
|
||||
/// The notification manager class.
|
||||
@property (nonatomic, strong, readonly, nullable) ZFPlayerNotification *notification;
|
||||
|
||||
/// The container view type.
|
||||
@property (nonatomic, assign, readonly) ZFPlayerContainerType containerType;
|
||||
|
||||
/// The player's small container view.
|
||||
@property (nonatomic, strong, readonly, nullable) ZFFloatView *smallFloatView;
|
||||
|
||||
/// Whether the small window is displayed.
|
||||
@property (nonatomic, assign, readonly) BOOL isSmallFloatViewShow;
|
||||
|
||||
/// The scroll view is `tableView` or `collectionView`.
|
||||
@property (nonatomic, weak, nullable) UIScrollView *scrollView;
|
||||
/*!
|
||||
@method playerWithPlayerManager:containerView:
|
||||
@abstract Create an ZFPlayerController that plays a single audiovisual item.
|
||||
@param playerManager must conform `ZFPlayerMediaPlayback` protocol.
|
||||
@param containerView to see the video frames must set the contrainerView.
|
||||
@result An instance of ZFPlayerController.
|
||||
*/
|
||||
+ (instancetype)playerWithPlayerManager:(id<ZFPlayerMediaPlayback>)playerManager containerView:(UIView *)containerView;
|
||||
|
||||
/*!
|
||||
@method initWithPlayerManager:containerView:
|
||||
@abstract Create an ZFPlayerController that plays a single audiovisual item.
|
||||
@param playerManager must conform `ZFPlayerMediaPlayback` protocol.
|
||||
@param containerView to see the video frames must set the contrainerView.
|
||||
@result An instance of ZFPlayerController.
|
||||
*/
|
||||
- (instancetype)initWithPlayerManager:(id<ZFPlayerMediaPlayback>)playerManager containerView:(UIView *)containerView;
|
||||
|
||||
/*!
|
||||
@method playerWithScrollView:playerManager:containerViewTag:
|
||||
@abstract Create an ZFPlayerController that plays a single audiovisual item. Use in `UITableView` or `UICollectionView`.
|
||||
@param scrollView is `tableView` or `collectionView`.
|
||||
@param playerManager must conform `ZFPlayerMediaPlayback` protocol.
|
||||
@param containerViewTag to see the video at scrollView must set the contrainerViewTag.
|
||||
@result An instance of ZFPlayerController.
|
||||
*/
|
||||
+ (instancetype)playerWithScrollView:(UIScrollView *)scrollView playerManager:(id<ZFPlayerMediaPlayback>)playerManager containerViewTag:(NSInteger)containerViewTag;
|
||||
|
||||
/*!
|
||||
@method initWithScrollView:playerManager:containerViewTag:
|
||||
@abstract Create an ZFPlayerController that plays a single audiovisual item. Use in `UITableView` or `UICollectionView`.
|
||||
@param scrollView is `tableView` or `collectionView`.
|
||||
@param playerManager must conform `ZFPlayerMediaPlayback` protocol.
|
||||
@param containerViewTag to see the video at scrollView must set the contrainerViewTag.
|
||||
@result An instance of ZFPlayerController.
|
||||
*/
|
||||
- (instancetype)initWithScrollView:(UIScrollView *)scrollView playerManager:(id<ZFPlayerMediaPlayback>)playerManager containerViewTag:(NSInteger)containerViewTag;
|
||||
|
||||
/*!
|
||||
@method playerWithScrollView:playerManager:containerView:
|
||||
@abstract Create an ZFPlayerController that plays a single audiovisual item. Use in `UIScrollView`.
|
||||
@param playerManager must conform `ZFPlayerMediaPlayback` protocol.
|
||||
@param containerView to see the video at the scrollView.
|
||||
@result An instance of ZFPlayerController.
|
||||
*/
|
||||
+ (instancetype)playerWithScrollView:(UIScrollView *)scrollView playerManager:(id<ZFPlayerMediaPlayback>)playerManager containerView:(UIView *)containerView;
|
||||
|
||||
/*!
|
||||
@method initWithScrollView:playerManager:containerView:
|
||||
@abstract Create an ZFPlayerController that plays a single audiovisual item. Use in `UIScrollView`.
|
||||
@param playerManager must conform `ZFPlayerMediaPlayback` protocol.
|
||||
@param containerView to see the video at the scrollView.
|
||||
@result An instance of ZFPlayerController.
|
||||
*/
|
||||
- (instancetype)initWithScrollView:(UIScrollView *)scrollView playerManager:(id<ZFPlayerMediaPlayback>)playerManager containerView:(UIView *)containerView;
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFPlayerController (ZFPlayerTimeControl)
|
||||
|
||||
/// The player current play time.
|
||||
@property (nonatomic, readonly) NSTimeInterval currentTime;
|
||||
|
||||
/// The player total time.
|
||||
@property (nonatomic, readonly) NSTimeInterval totalTime;
|
||||
|
||||
/// The player buffer time.
|
||||
@property (nonatomic, readonly) NSTimeInterval bufferTime;
|
||||
|
||||
/// The player progress, 0...1
|
||||
@property (nonatomic, readonly) float progress;
|
||||
|
||||
/// The player bufferProgress, 0...1
|
||||
@property (nonatomic, readonly) float bufferProgress;
|
||||
|
||||
/**
|
||||
Use this method to seek to a specified time for the current player and to be notified when the seek operation is complete.
|
||||
|
||||
@param time seek time.
|
||||
@param completionHandler completion handler.
|
||||
*/
|
||||
- (void)seekToTime:(NSTimeInterval)time completionHandler:(void (^ __nullable)(BOOL finished))completionHandler;
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFPlayerController (ZFPlayerPlaybackControl)
|
||||
|
||||
/// Resume playback record.default is NO.
|
||||
/// Memory storage playback records.
|
||||
@property (nonatomic, assign) BOOL resumePlayRecord;
|
||||
|
||||
/// 0...1.0
|
||||
/// Only affects audio volume for the device instance and not for the player.
|
||||
/// You can change device volume or player volume as needed,change the player volume you can conform the `ZFPlayerMediaPlayback` protocol.
|
||||
@property (nonatomic) float volume;
|
||||
|
||||
/// The device muted.
|
||||
/// Only affects audio muting for the device instance and not for the player.
|
||||
/// You can change device mute or player mute as needed,change the player mute you can conform the `ZFPlayerMediaPlayback` protocol.
|
||||
@property (nonatomic, getter=isMuted) BOOL muted;
|
||||
|
||||
// 0...1.0, where 1.0 is maximum brightness. Only supported by main screen.
|
||||
@property (nonatomic) float brightness;
|
||||
|
||||
/// The play asset URL.
|
||||
@property (nonatomic, nullable) NSURL *assetURL;
|
||||
|
||||
/// If tableView or collectionView has only one section , use `assetURLs`.
|
||||
/// If tableView or collectionView has more sections , use `sectionAssetURLs`.
|
||||
/// Set this you can use `playTheNext` `playThePrevious` `playTheIndex:` method.
|
||||
@property (nonatomic, copy, nullable) NSArray <NSURL *>*assetURLs;
|
||||
|
||||
/// The currently playing index,limited to one-dimensional arrays.
|
||||
@property (nonatomic) NSInteger currentPlayIndex;
|
||||
|
||||
/// is the last asset URL in `assetURLs`.
|
||||
@property (nonatomic, readonly) BOOL isLastAssetURL;
|
||||
|
||||
/// is the first asset URL in `assetURLs`.
|
||||
@property (nonatomic, readonly) BOOL isFirstAssetURL;
|
||||
|
||||
/// If Yes, player will be called pause method When Received `UIApplicationWillResignActiveNotification` notification.
|
||||
/// default is YES.
|
||||
@property (nonatomic) BOOL pauseWhenAppResignActive;
|
||||
|
||||
/// When the player is playing, it is paused by some event,not by user click to pause.
|
||||
/// For example, when the player is playing, application goes into the background or pushed to another viewController
|
||||
@property (nonatomic, getter=isPauseByEvent) BOOL pauseByEvent;
|
||||
|
||||
/// The current player controller is disappear, not dealloc
|
||||
@property (nonatomic, getter=isViewControllerDisappear) BOOL viewControllerDisappear;
|
||||
|
||||
/// You can custom the AVAudioSession,
|
||||
/// default is NO.
|
||||
@property (nonatomic, assign) BOOL customAudioSession;
|
||||
|
||||
/// The block invoked when the player is Prepare to play.
|
||||
@property (nonatomic, copy, nullable) void(^playerPrepareToPlay)(id<ZFPlayerMediaPlayback> asset, NSURL *assetURL);
|
||||
|
||||
/// The block invoked when the player is Ready to play.
|
||||
@property (nonatomic, copy, nullable) void(^playerReadyToPlay)(id<ZFPlayerMediaPlayback> asset, NSURL *assetURL);
|
||||
|
||||
/// The block invoked when the player play progress changed.
|
||||
@property (nonatomic, copy, nullable) void(^playerPlayTimeChanged)(id<ZFPlayerMediaPlayback> asset, NSTimeInterval currentTime, NSTimeInterval duration);
|
||||
|
||||
/// The block invoked when the player play buffer changed.
|
||||
@property (nonatomic, copy, nullable) void(^playerBufferTimeChanged)(id<ZFPlayerMediaPlayback> asset, NSTimeInterval bufferTime);
|
||||
|
||||
/// The block invoked when the player playback state changed.
|
||||
@property (nonatomic, copy, nullable) void(^playerPlayStateChanged)(id<ZFPlayerMediaPlayback> asset, ZFPlayerPlaybackState playState);
|
||||
|
||||
/// The block invoked when the player load state changed.
|
||||
@property (nonatomic, copy, nullable) void(^playerLoadStateChanged)(id<ZFPlayerMediaPlayback> asset, ZFPlayerLoadState loadState);
|
||||
|
||||
/// The block invoked when the player play failed.
|
||||
@property (nonatomic, copy, nullable) void(^playerPlayFailed)(id<ZFPlayerMediaPlayback> asset, id error);
|
||||
|
||||
/// The block invoked when the player play end.
|
||||
@property (nonatomic, copy, nullable) void(^playerDidToEnd)(id<ZFPlayerMediaPlayback> asset);
|
||||
|
||||
// The block invoked when video size changed.
|
||||
@property (nonatomic, copy, nullable) void(^presentationSizeChanged)(id<ZFPlayerMediaPlayback> asset, CGSize size);
|
||||
|
||||
/**
|
||||
Play the next url ,while the `assetURLs` is not NULL.
|
||||
*/
|
||||
- (void)playTheNext;
|
||||
|
||||
/**
|
||||
Play the previous url ,while the `assetURLs` is not NULL.
|
||||
*/
|
||||
- (void)playThePrevious;
|
||||
|
||||
/**
|
||||
Play the index of url ,while the `assetURLs` is not NULL.
|
||||
|
||||
@param index play the index.
|
||||
*/
|
||||
- (void)playTheIndex:(NSInteger)index;
|
||||
|
||||
/**
|
||||
Player stop and playerView remove from super view,remove other notification.
|
||||
*/
|
||||
- (void)stop;
|
||||
|
||||
/*!
|
||||
@method replaceCurrentPlayerManager:
|
||||
@abstract Replaces the player's current playeranager with the specified player item.
|
||||
@param manager must conform `ZFPlayerMediaPlayback` protocol
|
||||
@discussion The playerManager that will become the player's current playeranager.
|
||||
*/
|
||||
- (void)replaceCurrentPlayerManager:(id<ZFPlayerMediaPlayback>)manager;
|
||||
|
||||
/**
|
||||
Add video to cell.
|
||||
*/
|
||||
- (void)addPlayerViewToCell;
|
||||
|
||||
/**
|
||||
Add video to container view.
|
||||
*/
|
||||
- (void)addPlayerViewToContainerView:(UIView *)containerView;
|
||||
|
||||
/**
|
||||
Add to small float view.
|
||||
*/
|
||||
- (void)addPlayerViewToSmallFloatView;
|
||||
|
||||
/**
|
||||
Stop the current playing video and remove the playerView.
|
||||
*/
|
||||
- (void)stopCurrentPlayingView;
|
||||
|
||||
/**
|
||||
stop the current playing video on cell.
|
||||
*/
|
||||
- (void)stopCurrentPlayingCell;
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFPlayerController (ZFPlayerOrientationRotation)
|
||||
|
||||
@property (nonatomic, readonly) ZFOrientationObserver *orientationObserver;
|
||||
|
||||
/// Whether automatic screen rotation is supported.
|
||||
/// The value is NO.
|
||||
/// This property is used for the return value of UIViewController `shouldAutorotate` method.
|
||||
@property (nonatomic, readonly) BOOL shouldAutorotate;
|
||||
|
||||
/// Whether allow the video orientation rotate.
|
||||
/// default is YES.
|
||||
@property (nonatomic) BOOL allowOrentitaionRotation;
|
||||
|
||||
/// When ZFFullScreenMode is ZFFullScreenModeLandscape the orientation is LandscapeLeft or LandscapeRight, this value is YES.
|
||||
/// When ZFFullScreenMode is ZFFullScreenModePortrait, while the player fullSceen this value is YES.
|
||||
@property (nonatomic, readonly) BOOL isFullScreen;
|
||||
|
||||
/// when call the `stop` method, exit the fullScreen model, default is YES.
|
||||
@property (nonatomic, assign) BOOL exitFullScreenWhenStop;
|
||||
|
||||
/// Lock the screen orientation.
|
||||
@property (nonatomic, getter=isLockedScreen) BOOL lockedScreen;
|
||||
|
||||
/// The block invoked When player will rotate.
|
||||
@property (nonatomic, copy, nullable) void(^orientationWillChange)(ZFPlayerController *player, BOOL isFullScreen);
|
||||
|
||||
/// The block invoked when player rotated.
|
||||
@property (nonatomic, copy, nullable) void(^orientationDidChanged)(ZFPlayerController *player, BOOL isFullScreen);
|
||||
|
||||
/// default is UIStatusBarStyleLightContent.
|
||||
@property (nonatomic, assign) UIStatusBarStyle fullScreenStatusBarStyle;
|
||||
|
||||
/// defalut is UIStatusBarAnimationSlide.
|
||||
@property (nonatomic, assign) UIStatusBarAnimation fullScreenStatusBarAnimation;
|
||||
|
||||
/// The fullscreen statusbar hidden.
|
||||
@property (nonatomic, getter=isStatusBarHidden) BOOL statusBarHidden;
|
||||
|
||||
/**
|
||||
Add the device orientation observer.
|
||||
*/
|
||||
- (void)addDeviceOrientationObserver;
|
||||
|
||||
/**
|
||||
Remove the device orientation observer.
|
||||
*/
|
||||
- (void)removeDeviceOrientationObserver;
|
||||
|
||||
/**
|
||||
Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModeLandscape.
|
||||
|
||||
@param orientation is UIInterfaceOrientation.
|
||||
@param animated is animated.
|
||||
*/
|
||||
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModeLandscape.
|
||||
|
||||
@param orientation is UIInterfaceOrientation.
|
||||
@param animated is animated.
|
||||
@param completion rotating completed callback.
|
||||
*/
|
||||
- (void)rotateToOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated completion:(void(^ __nullable)(void))completion;
|
||||
|
||||
/**
|
||||
Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModePortrait.
|
||||
|
||||
@param fullScreen is fullscreen.
|
||||
@param animated is animated.
|
||||
@param completion rotating completed callback.
|
||||
*/
|
||||
- (void)enterPortraitFullScreen:(BOOL)fullScreen animated:(BOOL)animated completion:(void(^ __nullable)(void))completion;
|
||||
|
||||
/**
|
||||
Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModePortrait.
|
||||
|
||||
@param fullScreen is fullscreen.
|
||||
@param animated is animated.
|
||||
*/
|
||||
- (void)enterPortraitFullScreen:(BOOL)fullScreen animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
FullScreen mode is determined by ZFFullScreenMode.
|
||||
|
||||
@param fullScreen is fullscreen.
|
||||
@param animated is animated.
|
||||
@param completion rotating completed callback.
|
||||
*/
|
||||
- (void)enterFullScreen:(BOOL)fullScreen animated:(BOOL)animated completion:(void(^ __nullable)(void))completion;
|
||||
|
||||
/**
|
||||
FullScreen mode is determined by ZFFullScreenMode.
|
||||
|
||||
@param fullScreen is fullscreen.
|
||||
@param animated is animated.
|
||||
*/
|
||||
- (void)enterFullScreen:(BOOL)fullScreen animated:(BOOL)animated;
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFPlayerController (ZFPlayerViewGesture)
|
||||
|
||||
/// An instance of ZFPlayerGestureControl.
|
||||
@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;
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFPlayerController (ZFPlayerScrollView)
|
||||
|
||||
/// The scrollView player should auto player, default is YES.
|
||||
@property (nonatomic) BOOL shouldAutoPlay;
|
||||
|
||||
/// WWAN network auto play, only support in scrollView mode when the `shouldAutoPlay` is YES, default is NO.
|
||||
@property (nonatomic, getter=isWWANAutoPlay) BOOL WWANAutoPlay;
|
||||
|
||||
/// The indexPath is playing.
|
||||
@property (nonatomic, readonly, nullable) NSIndexPath *playingIndexPath;
|
||||
|
||||
/// The indexPath should be play while scrolling.
|
||||
@property (nonatomic, readonly, nullable) NSIndexPath *shouldPlayIndexPath;
|
||||
|
||||
/// The view tag that the player display in scrollView.
|
||||
@property (nonatomic, readonly) NSInteger containerViewTag;
|
||||
|
||||
/// The current playing cell stop playing when the cell has out off the screen,defalut is YES.
|
||||
@property (nonatomic) BOOL stopWhileNotVisible;
|
||||
|
||||
/**
|
||||
The current player scroll slides off the screen percent.
|
||||
the property used when the `stopWhileNotVisible` is YES, stop the current playing player.
|
||||
the property used when the `stopWhileNotVisible` is NO, the current playing player add to small container view.
|
||||
The range is 0.0~1.0, defalut is 0.5.
|
||||
0.0 is the player will disappear.
|
||||
1.0 is the player did disappear.
|
||||
*/
|
||||
@property (nonatomic) CGFloat playerDisapperaPercent;
|
||||
|
||||
/**
|
||||
The current player scroll to the screen percent to play the video.
|
||||
The range is 0.0~1.0, defalut is 0.0.
|
||||
0.0 is the player will appear.
|
||||
1.0 is the player did appear.
|
||||
*/
|
||||
@property (nonatomic) CGFloat playerApperaPercent;
|
||||
|
||||
/// If tableView or collectionView has more sections, use `sectionAssetURLs`.
|
||||
@property (nonatomic, copy, nullable) NSArray <NSArray <NSURL *>*>*sectionAssetURLs;
|
||||
|
||||
/// The block invoked When the player appearing.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerAppearingInScrollView)(NSIndexPath *indexPath, CGFloat playerApperaPercent);
|
||||
|
||||
/// The block invoked When the player disappearing.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerDisappearingInScrollView)(NSIndexPath *indexPath, CGFloat playerDisapperaPercent);
|
||||
|
||||
/// The block invoked When the player will appeared.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerWillAppearInScrollView)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player did appeared.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerDidAppearInScrollView)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player will disappear.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerWillDisappearInScrollView)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player did disappeared.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerDidDisappearInScrollView)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player should play.
|
||||
@property (nonatomic, copy, nullable) void(^zf_playerShouldPlayInScrollView)(NSIndexPath *indexPath);
|
||||
|
||||
/// The block invoked When the player did stop scroll.
|
||||
@property (nonatomic, copy, nullable) void(^zf_scrollViewDidEndScrollingCallback)(NSIndexPath *indexPath);
|
||||
|
||||
/// Filter the cell that should be played when the scroll is stopped (to play when the scroll is stopped).
|
||||
- (void)zf_filterShouldPlayCellWhileScrolled:(void (^ __nullable)(NSIndexPath *indexPath))handler;
|
||||
|
||||
/// Filter the cell that should be played while scrolling (you can use this to filter the highlighted cell).
|
||||
- (void)zf_filterShouldPlayCellWhileScrolling:(void (^ __nullable)(NSIndexPath *indexPath))handler;
|
||||
|
||||
/**
|
||||
Play the indexPath of url without scroll postion, while the `assetURLs` or `sectionAssetURLs` is not NULL.
|
||||
|
||||
@param indexPath Play the indexPath of url.
|
||||
*/
|
||||
- (void)playTheIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
/**
|
||||
Play the indexPath of url, while the `assetURLs` or `sectionAssetURLs` is not NULL.
|
||||
|
||||
@param indexPath Play the indexPath of url.
|
||||
@param scrollPosition scroll position.
|
||||
@param animated scroll animation.
|
||||
*/
|
||||
- (void)playTheIndexPath:(NSIndexPath *)indexPath
|
||||
scrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
|
||||
animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Play the indexPath of url with scroll postion, while the `assetURLs` or `sectionAssetURLs` is not NULL.
|
||||
|
||||
@param indexPath Play the indexPath of url.
|
||||
@param scrollPosition scroll position.
|
||||
@param animated scroll animation.
|
||||
@param completionHandler Scroll completion callback.
|
||||
*/
|
||||
- (void)playTheIndexPath:(NSIndexPath *)indexPath
|
||||
scrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
|
||||
animated:(BOOL)animated
|
||||
completionHandler:(void (^ __nullable)(void))completionHandler;
|
||||
|
||||
|
||||
/**
|
||||
Play the indexPath of url with scroll postion.
|
||||
|
||||
@param indexPath Play the indexPath of url
|
||||
@param assetURL The player URL.
|
||||
*/
|
||||
- (void)playTheIndexPath:(NSIndexPath *)indexPath assetURL:(NSURL *)assetURL;
|
||||
|
||||
|
||||
/**
|
||||
Play the indexPath of url with scroll postion.
|
||||
|
||||
@param indexPath Play the indexPath of url
|
||||
@param assetURL The player URL.
|
||||
@param scrollPosition scroll position.
|
||||
@param animated scroll animation.
|
||||
*/
|
||||
- (void)playTheIndexPath:(NSIndexPath *)indexPath
|
||||
assetURL:(NSURL *)assetURL
|
||||
scrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
|
||||
animated:(BOOL)animated;
|
||||
|
||||
/**
|
||||
Play the indexPath of url with scroll postion.
|
||||
|
||||
@param indexPath Play the indexPath of url
|
||||
@param assetURL The player URL.
|
||||
@param scrollPosition scroll position.
|
||||
@param animated scroll animation.
|
||||
@param completionHandler Scroll completion callback.
|
||||
*/
|
||||
- (void)playTheIndexPath:(NSIndexPath *)indexPath
|
||||
assetURL:(NSURL *)assetURL
|
||||
scrollPosition:(ZFPlayerScrollViewScrollPosition)scrollPosition
|
||||
animated:(BOOL)animated
|
||||
completionHandler:(void (^ __nullable)(void))completionHandler;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
@interface ZFPlayerController (ZFPlayerDeprecated)
|
||||
|
||||
/**
|
||||
Add the playerView to cell.
|
||||
*/
|
||||
- (void)updateScrollViewPlayerToCell __attribute__((deprecated("use `addPlayerViewToCell:` instead.")));
|
||||
|
||||
/**
|
||||
Add the playerView to containerView.
|
||||
|
||||
@param containerView The playerView containerView.
|
||||
*/
|
||||
- (void)updateNoramlPlayerWithContainerView:(UIView *)containerView __attribute__((deprecated("use `addPlayerViewToContainerView:` instead.")));
|
||||
|
||||
/**
|
||||
Play the indexPath of url ,while the `assetURLs` or `sectionAssetURLs` is not NULL.
|
||||
|
||||
@param indexPath Play the indexPath of url
|
||||
@param scrollToTop Scroll the current cell to top with animations.
|
||||
*/
|
||||
- (void)playTheIndexPath:(NSIndexPath *)indexPath scrollToTop:(BOOL)scrollToTop __attribute__((deprecated("use `playTheIndexPath:scrollPosition:animated:` instead.")));
|
||||
|
||||
/**
|
||||
Play the indexPath of url with scroll postion.
|
||||
|
||||
@param indexPath Play the indexPath of url
|
||||
@param assetURL The player URL.
|
||||
@param scrollToTop Scroll the current cell to top with animations.
|
||||
*/
|
||||
- (void)playTheIndexPath:(NSIndexPath *)indexPath assetURL:(NSURL *)assetURL scrollToTop:(BOOL)scrollToTop __attribute__((deprecated("use `playTheIndexPath:assetURL:scrollPosition:animated:` instead.")));
|
||||
|
||||
/**
|
||||
Play the indexPath of url ,while the `assetURLs` or `sectionAssetURLs` is not NULL.
|
||||
|
||||
@param indexPath Play the indexPath of url
|
||||
@param scrollToTop scroll the current cell to top with animations.
|
||||
@param completionHandler Scroll completion callback.
|
||||
*/
|
||||
- (void)playTheIndexPath:(NSIndexPath *)indexPath scrollToTop:(BOOL)scrollToTop completionHandler:(void (^ __nullable)(void))completionHandler __attribute__((deprecated("use `playTheIndexPath:scrollPosition:animated:completionHandler:` instead.")));
|
||||
|
||||
/**
|
||||
Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModeLandscape.
|
||||
|
||||
@param orientation UIInterfaceOrientation
|
||||
@param animated is animated.
|
||||
@param completion rotating completed callback.
|
||||
*/
|
||||
- (void)enterLandscapeFullScreen:(UIInterfaceOrientation)orientation animated:(BOOL)animated completion:(void(^ __nullable)(void))completion __attribute__((deprecated("use `rotateToOrientation:animated:completion:` instead.")));
|
||||
|
||||
/**
|
||||
Enter the fullScreen while the ZFFullScreenMode is ZFFullScreenModeLandscape.
|
||||
|
||||
@param orientation UIInterfaceOrientation
|
||||
@param animated is animated.
|
||||
*/
|
||||
- (void)enterLandscapeFullScreen:(UIInterfaceOrientation)orientation animated:(BOOL)animated __attribute__((deprecated("use `rotateToOrientation:animated:` instead.")));
|
||||
|
||||
/**
|
||||
Add to the keyWindow.
|
||||
*/
|
||||
- (void)addPlayerViewToKeyWindow __attribute__((deprecated("use `addPlayerViewToSmallFloatView` instead.")));;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
1436
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFPlayerController.m
generated
Normal file
137
Pods/ZFPlayer/ZFPlayer/Classes/Core/ZFPlayerGestureControl.h
generated
Executable file
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// ZFPlayerGestureControl.h
|
||||
// ZFPlayer
|
||||
//
|
||||
// Copyright (c) 2016年 任子丰 ( http://github.com/renzifeng )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ZFPlayerGestureType) {
|
||||
ZFPlayerGestureTypeUnknown,
|
||||
ZFPlayerGestureTypeSingleTap,
|
||||
ZFPlayerGestureTypeDoubleTap,
|
||||
ZFPlayerGestureTypePan,
|
||||
ZFPlayerGestureTypePinch
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ZFPanDirection) {
|
||||
ZFPanDirectionUnknown,
|
||||
ZFPanDirectionV,
|
||||
ZFPanDirectionH,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ZFPanLocation) {
|
||||
ZFPanLocationUnknown,
|
||||
ZFPanLocationLeft,
|
||||
ZFPanLocationRight,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ZFPanMovingDirection) {
|
||||
ZFPanMovingDirectionUnkown,
|
||||
ZFPanMovingDirectionTop,
|
||||
ZFPanMovingDirectionLeft,
|
||||
ZFPanMovingDirectionBottom,
|
||||
ZFPanMovingDirectionRight,
|
||||
};
|
||||
|
||||
/// This enumeration lists some of the gesture types that the player has by default.
|
||||
typedef NS_OPTIONS(NSUInteger, ZFPlayerDisableGestureTypes) {
|
||||
ZFPlayerDisableGestureTypesNone = 0,
|
||||
ZFPlayerDisableGestureTypesSingleTap = 1 << 0,
|
||||
ZFPlayerDisableGestureTypesDoubleTap = 1 << 1,
|
||||
ZFPlayerDisableGestureTypesPan = 1 << 2,
|
||||
ZFPlayerDisableGestureTypesPinch = 1 << 3,
|
||||
ZFPlayerDisableGestureTypesAll = (ZFPlayerDisableGestureTypesSingleTap | ZFPlayerDisableGestureTypesDoubleTap | ZFPlayerDisableGestureTypesPan | ZFPlayerDisableGestureTypesPinch)
|
||||
};
|
||||
|
||||
/// This enumeration lists some of the pan gesture moving direction that the player not support.
|
||||
typedef NS_OPTIONS(NSUInteger, ZFPlayerDisablePanMovingDirection) {
|
||||
ZFPlayerDisablePanMovingDirectionNone = 0, /// Not disable pan moving direction.
|
||||
ZFPlayerDisablePanMovingDirectionVertical = 1 << 0, /// Disable pan moving vertical direction.
|
||||
ZFPlayerDisablePanMovingDirectionHorizontal = 1 << 1, /// Disable pan moving horizontal direction.
|
||||
ZFPlayerDisablePanMovingDirectionAll = (ZFPlayerDisablePanMovingDirectionVertical | ZFPlayerDisablePanMovingDirectionHorizontal) /// Disable pan moving all direction.
|
||||
};
|
||||
|
||||
@interface ZFPlayerGestureControl : NSObject
|
||||
|
||||
/// Gesture condition callback.
|
||||
@property (nonatomic, copy, nullable) BOOL(^triggerCondition)(ZFPlayerGestureControl *control, ZFPlayerGestureType type, UIGestureRecognizer *gesture, UITouch *touch);
|
||||
|
||||
/// Single tap gesture callback.
|
||||
@property (nonatomic, copy, nullable) void(^singleTapped)(ZFPlayerGestureControl *control);
|
||||
|
||||
/// Double tap gesture callback.
|
||||
@property (nonatomic, copy, nullable) void(^doubleTapped)(ZFPlayerGestureControl *control);
|
||||
|
||||
/// Begin pan gesture callback.
|
||||
@property (nonatomic, copy, nullable) void(^beganPan)(ZFPlayerGestureControl *control, ZFPanDirection direction, ZFPanLocation location);
|
||||
|
||||
/// Pan gesture changing callback.
|
||||
@property (nonatomic, copy, nullable) void(^changedPan)(ZFPlayerGestureControl *control, ZFPanDirection direction, ZFPanLocation location, CGPoint velocity);
|
||||
|
||||
/// End the Pan gesture callback.
|
||||
@property (nonatomic, copy, nullable) void(^endedPan)(ZFPlayerGestureControl *control, ZFPanDirection direction, ZFPanLocation location);
|
||||
|
||||
/// Pinch gesture callback.
|
||||
@property (nonatomic, copy, nullable) void(^pinched)(ZFPlayerGestureControl *control, float scale);
|
||||
|
||||
/// The single tap gesture.
|
||||
@property (nonatomic, strong, readonly) UITapGestureRecognizer *singleTap;
|
||||
|
||||
/// The double tap gesture.
|
||||
@property (nonatomic, strong, readonly) UITapGestureRecognizer *doubleTap;
|
||||
|
||||
/// The pan tap gesture.
|
||||
@property (nonatomic, strong, readonly) UIPanGestureRecognizer *panGR;
|
||||
|
||||
/// The pinch tap gesture.
|
||||
@property (nonatomic, strong, readonly) UIPinchGestureRecognizer *pinchGR;
|
||||
|
||||
/// The pan gesture direction.
|
||||
@property (nonatomic, readonly) ZFPanDirection panDirection;
|
||||
|
||||
/// The pan location.
|
||||
@property (nonatomic, readonly) ZFPanLocation panLocation;
|
||||
|
||||
/// The moving drection.
|
||||
@property (nonatomic, readonly) ZFPanMovingDirection panMovingDirection;
|
||||
|
||||
/// The gesture types that the player not support.
|
||||
@property (nonatomic) ZFPlayerDisableGestureTypes disableTypes;
|
||||
|
||||
/// The pan gesture moving direction that the player not support.
|
||||
@property (nonatomic) ZFPlayerDisablePanMovingDirection disablePanMovingDirection;
|
||||
|
||||
/**
|
||||
Add all gestures(singleTap、doubleTap、panGR、pinchGR) to the view.
|
||||
*/
|
||||
- (void)addGestureToView:(UIView *)view;
|
||||
|
||||
/**
|
||||
Remove all gestures(singleTap、doubleTap、panGR、pinchGR) form the view.
|
||||
*/
|
||||
- (void)removeGestureToView:(UIView *)view;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||