This commit is contained in:
DDIsFriend
2023-08-28 18:29:21 +08:00
parent c73a6ff1d4
commit 8d563860f1
290 changed files with 9542 additions and 9626 deletions

View File

@@ -1,44 +0,0 @@
//
// 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

View File

@@ -1,527 +0,0 @@
//
// 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 {
// playbackBufferEmptybufferingOneSecondbufferingSomeSecond
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

View File

@@ -1,127 +0,0 @@
//
// 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

View File

@@ -1,411 +0,0 @@
//
// 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

View File

@@ -1,45 +0,0 @@
//
// 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

View File

@@ -1,149 +0,0 @@
//
// 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

View File

@@ -1,126 +0,0 @@
//
// 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

View File

@@ -1,501 +0,0 @@
//
// 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

View File

@@ -1,66 +0,0 @@
//
// 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

View File

@@ -1,183 +0,0 @@
//
// 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

View File

@@ -1,39 +0,0 @@
//
// 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

View File

@@ -1,167 +0,0 @@
//
// 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 572 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 761 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@@ -1,154 +0,0 @@
//
// 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

View File

@@ -1,831 +0,0 @@
//
// 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

View File

@@ -1,42 +0,0 @@
//
// 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

View File

@@ -1,392 +0,0 @@
//
// 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
/// signaturecrash
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

View File

@@ -1,111 +0,0 @@
//
// 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

View File

@@ -1,387 +0,0 @@
//
// 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

View File

@@ -1,118 +0,0 @@
//
// 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

View File

@@ -1,426 +0,0 @@
//
// 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);
// boundsyes
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;
// value0-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

View File

@@ -1,31 +0,0 @@
//
// 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

View File

@@ -1,72 +0,0 @@
//
// 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

View File

@@ -1,27 +0,0 @@
//
// 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

View File

@@ -1,117 +0,0 @@
//
// 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

View File

@@ -1,52 +0,0 @@
//
// 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

View File

@@ -1,74 +0,0 @@
//
// 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

View File

@@ -1,46 +0,0 @@
//
// 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

View File

@@ -1,162 +0,0 @@
//
// 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

View File

@@ -1,45 +0,0 @@
//
// ZFIJKPlayerManager.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>
#if __has_include(<ZFPlayer/ZFPlayerMediaPlayback.h>)
#import <ZFPlayer/ZFPlayerMediaPlayback.h>
#else
#import "ZFPlayerMediaPlayback.h"
#endif
#if __has_include(<IJKMediaFramework/IJKMediaFramework.h>)
#import <IJKMediaFramework/IJKMediaFramework.h>
@interface ZFIJKPlayerManager : NSObject <ZFPlayerMediaPlayback>
@property (nonatomic, strong, readonly) IJKFFMoviePlayerController *player;
@property (nonatomic, strong, readonly) IJKFFOptions *options;
@property (nonatomic, assign) NSTimeInterval timeRefreshInterval;
@end
#endif

View File

@@ -1,458 +0,0 @@
//
// ZFIJKPlayerManager.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 "ZFIJKPlayerManager.h"
#if __has_include(<ZFPlayer/ZFPlayer.h>)
#import <ZFPlayer/ZFPlayer.h>
#import <ZFPlayer/ZFPlayerConst.h>
#else
#import "ZFPlayer.h"
#import "ZFPlayerConst.h"
#endif
#if __has_include(<IJKMediaFramework/IJKMediaFramework.h>)
@interface ZFIJKPlayerManager ()
@property (nonatomic, strong) IJKFFMoviePlayerController *player;
@property (nonatomic, strong) IJKFFOptions *options;
@property (nonatomic, assign) CGFloat lastVolume;
@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, assign) BOOL isReadyToPlay;
@end
@implementation ZFIJKPlayerManager
@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;
- (void)dealloc {
[self stop];
}
- (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 prepareToPlay];
}
- (void)play {
if (!_isPreparedToPlay) {
[self prepareToPlay];
} else {
[self.player play];
if (self.timer) [self.timer setFireDate:[NSDate date]];
self.player.playbackRate = self.rate;
_isPlaying = YES;
self.playState = ZFPlayerPlayStatePlaying;
}
}
- (void)pause {
if (self.timer) [self.timer setFireDate:[NSDate distantFuture]];
[self.player pause];
_isPlaying = NO;
self.playState = ZFPlayerPlayStatePaused;
}
- (void)stop {
[self removeMovieNotificationObservers];
[self.player shutdown];
[self.player.view removeFromSuperview];
self.player = nil;
_assetURL = nil;
[self.timer invalidate];
self.presentationSize = CGSizeZero;
self.timer = nil;
_isPlaying = NO;
_isPreparedToPlay = NO;
self->_currentTime = 0;
self->_totalTime = 0;
self->_bufferTime = 0;
self.isReadyToPlay = NO;
self.playState = ZFPlayerPlayStatePlayStopped;
}
- (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.player.duration > 0) {
self.player.currentPlaybackTime = time;
if (completionHandler) completionHandler(YES);
} else {
self.seekTime = time;
}
}
- (UIImage *)thumbnailImageAtCurrentTime {
return [self.player thumbnailImageAtCurrentTime];
}
#pragma mark - private method
- (void)initializePlayer {
// IJKFFMoviePlayerController
if (self.player) {
[self removeMovieNotificationObservers];
[self.player shutdown];
[self.player.view removeFromSuperview];
self.player = nil;
}
self.player = [[IJKFFMoviePlayerController alloc] initWithContentURL:self.assetURL withOptions:self.options];
self.player.shouldAutoplay = self.shouldAutoPlay;
[self.player prepareToPlay];
self.view.playerView = self.player.view;
self.scalingMode = self->_scalingMode;
[self addPlayerNotificationObservers];
}
- (void)addPlayerNotificationObservers {
///
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(loadStateDidChange:)
name:IJKMPMoviePlayerLoadStateDidChangeNotification
object:_player];
/// 退
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayBackFinish:)
name:IJKMPMoviePlayerPlaybackDidFinishNotification
object:_player];
///
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(mediaIsPreparedToPlayDidChange:)
name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
object:_player];
///
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(moviePlayBackStateDidChange:)
name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
object:_player];
///
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sizeAvailableChange:)
name:IJKMPMovieNaturalSizeAvailableNotification
object:self.player];
}
- (void)removeMovieNotificationObservers {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:IJKMPMoviePlayerLoadStateDidChangeNotification
object:_player];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:IJKMPMoviePlayerPlaybackDidFinishNotification
object:_player];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:IJKMPMediaPlaybackIsPreparedToPlayDidChangeNotification
object:_player];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:IJKMPMoviePlayerPlaybackStateDidChangeNotification
object:_player];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:IJKMPMovieNaturalSizeAvailableNotification
object:_player];
}
- (void)timerUpdate {
if (self.player.currentPlaybackTime > 0 && !self.isReadyToPlay) {
self.isReadyToPlay = YES;
self.loadState = ZFPlayerLoadStatePlaythroughOK;
}
self->_currentTime = self.player.currentPlaybackTime > 0 ? self.player.currentPlaybackTime : 0;
self->_totalTime = self.player.duration;
self->_bufferTime = self.player.playableDuration;
if (self.playerPlayTimeChanged) self.playerPlayTimeChanged(self, self.currentTime, self.totalTime);
if (self.playerBufferTimeChanged) self.playerBufferTimeChanged(self, self.bufferTime);
}
#pragma - notification
///
- (void)moviePlayBackFinish:(NSNotification *)notification {
int reason = [[[notification userInfo] valueForKey:IJKMPMoviePlayerPlaybackDidFinishReasonUserInfoKey] intValue];
switch (reason) {
case IJKMPMovieFinishReasonPlaybackEnded: {
ZFPlayerLog(@"playbackStateDidChange: 播放完毕: %d\n", reason);
self.playState = ZFPlayerPlayStatePlayStopped;
if (self.playerDidToEnd) self.playerDidToEnd(self);
}
break;
case IJKMPMovieFinishReasonUserExited: {
ZFPlayerLog(@"playbackStateDidChange: 用户退出播放: %d\n", reason);
}
break;
case IJKMPMovieFinishReasonPlaybackError: {
ZFPlayerLog(@"playbackStateDidChange: 播放出现错误: %d\n", reason);
self.playState = ZFPlayerPlayStatePlayFailed;
if (self.playerPlayFailed) self.playerPlayFailed(self, @(reason));
}
break;
default:
ZFPlayerLog(@"playbackPlayBackDidFinish: ???: %d\n", reason);
break;
}
}
//
- (void)mediaIsPreparedToPlayDidChange:(NSNotification *)notification {
ZFPlayerLog(@"加载状态变成了已经缓存完成,如果设置了自动播放, 会自动播放");
//
if (!self.timer) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:self.timeRefreshInterval > 0 ? self.timeRefreshInterval : 0.1 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
if (self.isPlaying) {
[self play];
self.muted = self.muted;
if (self.seekTime > 0) {
[self seekToTime:self.seekTime completionHandler:nil];
self.seekTime = 0; // ,
[self play];
}
}
if (self.playerReadyToPlay) self.playerReadyToPlay(self, self.assetURL);
}
#pragma mark -
/**
IJKMPMovieLoadStateUnknown == 0
IJKMPMovieLoadStatePlayable == 1
IJKMPMovieLoadStatePlaythroughOK == 2
IJKMPMovieLoadStateStalled == 4
*/
- (void)loadStateDidChange:(NSNotification*)notification {
IJKMPMovieLoadState loadState = self.player.loadState;
if ((loadState & IJKMPMovieLoadStatePlayable)) {
ZFPlayerLog(@"加载状态变成了缓存数据足够开始播放,但是视频并没有缓存完全");
if (self.player.currentPlaybackTime > 0) {
self.loadState = ZFPlayerLoadStatePlayable;
}
} else if ((loadState & IJKMPMovieLoadStatePlaythroughOK)) {
//
ZFPlayerLog(@"加载状态变成了已经缓存完成,如果设置了自动播放, 会自动播放");
} else if ((loadState & IJKMPMovieLoadStateStalled)) {
//
ZFPlayerLog(@"网速不好等因素导致了暂停");
self.loadState = ZFPlayerLoadStateStalled;
} else {
ZFPlayerLog(@"加载状态变成了未知状态");
self.loadState = ZFPlayerLoadStateUnknown;
}
}
//
- (void)moviePlayBackStateDidChange:(NSNotification *)notification {
switch (self.player.playbackState) {
case IJKMPMoviePlaybackStateStopped: {
ZFPlayerLog(@"播放器的播放状态变了,现在是停止状态 %d: stoped", (int)_player.playbackState);
// (, ), ,
self.playState = ZFPlayerPlayStatePlayStopped;
}
break;
case IJKMPMoviePlaybackStatePlaying: {
ZFPlayerLog(@"播放器的播放状态变了,现在是播放状态 %d: playing", (int)_player.playbackState);
}
break;
case IJKMPMoviePlaybackStatePaused: {
ZFPlayerLog(@"播放器的播放状态变了,现在是暂停状态 %d: paused", (int)_player.playbackState);
}
break;
case IJKMPMoviePlaybackStateInterrupted: {
ZFPlayerLog(@"播放器的播放状态变了,现在是中断状态 %d: interrupted", (int)_player.playbackState);
}
break;
case IJKMPMoviePlaybackStateSeekingForward: {
ZFPlayerLog(@"播放器的播放状态变了,现在是向前拖动状态:%d forward",(int)self.player.playbackState);
}
break;
case IJKMPMoviePlaybackStateSeekingBackward: {
ZFPlayerLog(@"放器的播放状态变了,现在是向后拖动状态 %d: backward", (int)_player.playbackState);
}
break;
default: {
ZFPlayerLog(@"播放器的播放状态变了,现在是未知状态 %d: unknown", (int)_player.playbackState);
}
break;
}
}
///
- (void)sizeAvailableChange:(NSNotification *)notify {
self.presentationSize = self.player.naturalSize;
self.view.presentationSize = self.presentationSize;
if (self.presentationSizeChanged) {
self.presentationSizeChanged(self, self->_presentationSize);
}
}
#pragma mark - getter
- (ZFPlayerView *)view {
if (!_view) {
_view = [[ZFPlayerView alloc] init];
}
return _view;
}
- (float)rate {
return _rate == 0 ?1:_rate;
}
- (IJKFFOptions *)options {
if (!_options) {
_options = [IJKFFOptions optionsByDefault];
/// seek
[_options setPlayerOptionIntValue:1 forKey:@"enable-accurate-seek"];
/// http
[_options setOptionIntValue:1 forKey:@"dns_cache_clear" ofCategory:kIJKFFOptionCategoryFormat];
}
return _options;
}
#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.playbackRate) > 0.00001f) {
self.player.playbackRate = rate;
}
}
- (void)setMuted:(BOOL)muted {
_muted = muted;
if (muted) {
self.lastVolume = self.player.playbackVolume;
self.player.playbackVolume = 0;
} else {
/// Fix first called the lastVolume is 0.
if (self.lastVolume == 0) self.lastVolume = self.player.playbackVolume;
self.player.playbackVolume = self.lastVolume;
}
}
- (void)setScalingMode:(ZFPlayerScalingMode)scalingMode {
_scalingMode = scalingMode;
self.view.scalingMode = scalingMode;
switch (scalingMode) {
case ZFPlayerScalingModeNone:
self.player.scalingMode = IJKMPMovieScalingModeNone;
break;
case ZFPlayerScalingModeAspectFit:
self.player.scalingMode = IJKMPMovieScalingModeAspectFit;
break;
case ZFPlayerScalingModeAspectFill:
self.player.scalingMode = IJKMPMovieScalingModeAspectFill;
break;
case ZFPlayerScalingModeFill:
self.player.scalingMode = IJKMPMovieScalingModeFill;
break;
default:
break;
}
}
- (void)setVolume:(float)volume {
_volume = MIN(MAX(0, volume), 1);
self.player.playbackVolume = _volume;
}
@end
#endif