diff --git a/SJVideoPlayer.podspec b/SJVideoPlayer.podspec index 3e9d48af3..a0a4f9ab4 100644 --- a/SJVideoPlayer.podspec +++ b/SJVideoPlayer.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| s.name = 'SJVideoPlayer' -s.version = '2.0.3.7' +s.version = '2.0.3.8' s.summary = 'video player.' s.description = 'https://github.com/changsanjiang/SJVideoPlayer/blob/master/README.md' s.homepage = 'https://github.com/changsanjiang/SJVideoPlayer' diff --git a/SJVideoPlayer/.DS_Store b/SJVideoPlayer/.DS_Store index 0df626b02..0fab8d4c8 100755 Binary files a/SJVideoPlayer/.DS_Store and b/SJVideoPlayer/.DS_Store differ diff --git a/SJVideoPlayer/ControlView/SJVideoPlayerFilmEditingControlView.h b/SJVideoPlayer/ControlView/SJVideoPlayerFilmEditingControlView.h index 39c354c27..b2d7e3989 100644 --- a/SJVideoPlayer/ControlView/SJVideoPlayerFilmEditingControlView.h +++ b/SJVideoPlayer/ControlView/SJVideoPlayerFilmEditingControlView.h @@ -16,11 +16,11 @@ typedef NS_ENUM(NSUInteger, SJVideoPlayerFilmEditingViewTag) { SJVideoPlayerFilmEditingViewTag_Export, }; -typedef NS_ENUM(NSUInteger, SJVideoPlayerFilmEditingRecrodStatus) { - SJVideoPlayerFilmEditingRecrodStatus_Unknown, - SJVideoPlayerFilmEditingRecrodStatus_Recording, - SJVideoPlayerFilmEditingRecrodStatus_Finished, - SJVideoPlayerFilmEditingRecrodStatus_Paused, +typedef NS_ENUM(NSUInteger, SJVideoPlayerFilmEditingStatus) { + SJVideoPlayerFilmEditingStatus_Unknown, + SJVideoPlayerFilmEditingStatus_Recording, + SJVideoPlayerFilmEditingStatus_Finished, // screenshot finished || record finished + SJVideoPlayerFilmEditingStatus_Paused, }; @interface SJVideoPlayerFilmEditingControlView : UIView @@ -38,7 +38,7 @@ typedef NS_ENUM(NSUInteger, SJVideoPlayerFilmEditingRecrodStatus) { #pragma mark - record -@property (nonatomic, readonly) SJVideoPlayerFilmEditingRecrodStatus recordStatus; +@property (nonatomic, readonly) SJVideoPlayerFilmEditingStatus recordStatus; - (void)pauseRecording; - (void)resumeRecording; - (void)completeRecording; diff --git a/SJVideoPlayer/ControlView/SJVideoPlayerFilmEditingControlView.m b/SJVideoPlayer/ControlView/SJVideoPlayerFilmEditingControlView.m index eb0a2292b..0ade6d408 100644 --- a/SJVideoPlayer/ControlView/SJVideoPlayerFilmEditingControlView.m +++ b/SJVideoPlayer/ControlView/SJVideoPlayerFilmEditingControlView.m @@ -25,7 +25,7 @@ @interface SJVideoPlayerFilmEditingControlView () @property (nonatomic, strong, readonly) SJVideoPlayerFilmEditingRecordView *recordView; @property (nonatomic, strong, readonly) UITapGestureRecognizer *tapGR; @property (nonatomic, weak, readwrite) SJFilmEditingResultUploader *uploader; -@property (nonatomic, readwrite) SJVideoPlayerFilmEditingRecrodStatus recordStatus; +@property (nonatomic, readwrite) SJVideoPlayerFilmEditingStatus recordStatus; @end NS_ASSUME_NONNULL_END @@ -56,13 +56,13 @@ - (void)clickedBtn:(UIButton *)btn { switch ( btn.tag ) { // screenshot case SJVideoPlayerFilmEditingViewTag_Screenshot: { - _recordStatus = SJVideoPlayerFilmEditingRecrodStatus_Unknown; + _recordStatus = SJVideoPlayerFilmEditingStatus_Finished; [self _showResultWithType:SJVideoPlayerFilmEditingResultViewType_Screenshot]; } break; // export case SJVideoPlayerFilmEditingViewTag_Export: { - _recordStatus = SJVideoPlayerFilmEditingRecrodStatus_Recording; + _recordStatus = SJVideoPlayerFilmEditingStatus_Recording; if ( _startRecordingExeBlock ) _startRecordingExeBlock(self); self.recordView.tipsText = _recordTipsText; _recordView.waitingForRecordingTipsText = _waitingForRecordingTipsText; @@ -84,17 +84,17 @@ - (void)clickedBtn:(UIButton *)btn { } - (void)pauseRecording { - _recordStatus = SJVideoPlayerFilmEditingRecrodStatus_Paused; + _recordStatus = SJVideoPlayerFilmEditingStatus_Paused; [_recordView pause]; } - (void)resumeRecording { - _recordStatus = SJVideoPlayerFilmEditingRecrodStatus_Recording; + _recordStatus = SJVideoPlayerFilmEditingStatus_Recording; [_recordView resume]; } - (void)completeRecording { - _recordStatus = SJVideoPlayerFilmEditingRecrodStatus_Finished; + _recordStatus = SJVideoPlayerFilmEditingStatus_Finished; [_recordView stop]; [self _showResultWithType:SJVideoPlayerFilmEditingResultViewType_Video]; } diff --git a/SJVideoPlayer/ControlView/UIView+SJControlAdd.m b/SJVideoPlayer/ControlView/UIView+SJControlAdd.m index ae2aefa45..a365d093b 100755 --- a/SJVideoPlayer/ControlView/UIView+SJControlAdd.m +++ b/SJVideoPlayer/ControlView/UIView+SJControlAdd.m @@ -81,6 +81,8 @@ - (void)__changeState:(BOOL)show { self.alpha = 0.001; } } + + self.appearState = show; if ( show ) { if ( self.appearExeBlock ) self.appearExeBlock(self); @@ -88,8 +90,7 @@ - (void)__changeState:(BOOL)show { else { if ( self.disappearExeBlock ) self.disappearExeBlock(self); } - - self.appearState = show; + } @end diff --git a/SJVideoPlayer/LightweightControlView/SJLightweightBottomControlView.h b/SJVideoPlayer/LightweightControlView/SJLightweightBottomControlView.h new file mode 100644 index 000000000..98afd1b16 --- /dev/null +++ b/SJVideoPlayer/LightweightControlView/SJLightweightBottomControlView.h @@ -0,0 +1,49 @@ +// +// SJLightweightBottomControlView.h +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN +typedef NS_ENUM(NSUInteger, SJLightweightBottomControlViewTag) { + SJLightweightBottomControlViewTag_Play, + SJLightweightBottomControlViewTag_Pause, + SJLightweightBottomControlViewTag_Full, +}; + +@protocol SJLightweightBottomControlViewDelegate; + +@interface SJLightweightBottomControlView : UIView + +@property (nonatomic, weak, readwrite, nullable) id delegate; + +@property (nonatomic) BOOL isFullscreen; + +@property (nonatomic) float progress; + +@property (nonatomic) float bufferProgress; + +@property (nonatomic, getter=isStopped) BOOL stopped; + +- (void)setCurrentTimeStr:(NSString *)currentTimeStr; +- (void)setCurrentTimeStr:(NSString *)currentTimeStr totalTimeStr:(NSString *)totalTimeStr; + +@end + +@protocol SJLightweightBottomControlViewDelegate + +@optional +- (void)bottomControlView:(SJLightweightBottomControlView *)bottomControlView clickedViewTag:(SJLightweightBottomControlViewTag)tag; + +- (void)sliderWillBeginDraggingForBottomView:(SJLightweightBottomControlView *)view; + +- (void)bottomView:(SJLightweightBottomControlView *)view sliderDidDrag:(CGFloat)value; + +- (void)sliderDidEndDraggingForBottomView:(SJLightweightBottomControlView *)view; + +@end +NS_ASSUME_NONNULL_END diff --git a/SJVideoPlayer/LightweightControlView/SJLightweightBottomControlView.m b/SJVideoPlayer/LightweightControlView/SJLightweightBottomControlView.m new file mode 100644 index 000000000..bebe88023 --- /dev/null +++ b/SJVideoPlayer/LightweightControlView/SJLightweightBottomControlView.m @@ -0,0 +1,243 @@ +// +// SJLightweightBottomControlView.m +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import "SJLightweightBottomControlView.h" +#import +#import +#import +#import "SJVideoPlayerControlMaskView.h" +#import "UIView+SJVideoPlayerSetting.h" + +@interface SJLightweightBottomControlView () + +@property (nonatomic, strong, readonly) UIButton *playBtn; +@property (nonatomic, strong, readonly) UIButton *pauseBtn; +@property (nonatomic, strong, readonly) UILabel *currentTimeLabel; +@property (nonatomic, strong, readonly) UILabel *separateLabel; +@property (nonatomic, strong, readonly) UILabel *durationTimeLabel; +@property (nonatomic, strong, readonly) SJSlider *progressSlider; +@property (nonatomic, strong, readonly) UIButton *fullBtn; + +@end + +@implementation SJLightweightBottomControlView +@synthesize separateLabel = _separateLabel; +@synthesize durationTimeLabel = _durationTimeLabel; +@synthesize playBtn = _playBtn; +@synthesize pauseBtn = _pauseBtn; +@synthesize currentTimeLabel = _currentTimeLabel; +@synthesize progressSlider = _progressSlider; +@synthesize fullBtn = _fullBtn; + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if ( !self ) return nil; + [self _bottomSetupView]; + [self _bottomSettingHelper]; + [self setStopped:YES]; + return self; +} + +- (CGSize)intrinsicContentSize { + if ( _isFullscreen ) { + if ( SJ_is_iPhoneX() ) return CGSizeMake(SJScreen_Max(), 60); + else return CGSizeMake(SJScreen_Max(), 49); + } + + return CGSizeMake(SJScreen_Min(), 49); +} + +- (void)setIsFullscreen:(BOOL)isFullscreen { + _isFullscreen = isFullscreen; + [self invalidateIntrinsicContentSize]; +} + +- (void)setStopped:(BOOL)stopped { + _stopped = stopped; + [UIView animateWithDuration:0.3 animations:^{ + if ( stopped ) { + self.playBtn.alpha = 1; + self.pauseBtn.alpha = 0.001; + } + else { + self.playBtn.alpha = 0.001; + self.pauseBtn.alpha = 1; + } + }]; +} + +- (void)setCurrentTimeStr:(NSString *)currentTimeStr { + self.currentTimeLabel.text = currentTimeStr; +} + +- (void)setCurrentTimeStr:(NSString *)currentTimeStr totalTimeStr:(NSString *)totalTimeStr { + self.currentTimeLabel.text = currentTimeStr; + self.durationTimeLabel.text = totalTimeStr; +} + +- (void)clickedBtn:(UIButton *)btn { + if ( ![_delegate respondsToSelector:@selector(bottomControlView:clickedViewTag:)] ) return; + [_delegate bottomControlView:self clickedViewTag:btn.tag]; +} + +- (void)setProgress:(float)progress { + if ( self.progressSlider.isDragging ) return; + self.progressSlider.value = progress; +} + +- (float)progress { + return self.progressSlider.value; +} + +- (void)setBufferProgress:(float)bufferProgress { + self.progressSlider.bufferProgress = bufferProgress; +} + +- (float)bufferProgress { + return self.progressSlider.bufferProgress; +} + +#pragma mark - + +- (void)_bottomSetupView { + [self addSubview:self.playBtn]; + [self addSubview:self.pauseBtn]; + [self addSubview:self.currentTimeLabel]; + [self addSubview:self.separateLabel]; + [self addSubview:self.durationTimeLabel]; + [self addSubview:self.progressSlider]; + [self addSubview:self.fullBtn]; + + [_playBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.leading.offset(0); + make.size.offset(49); + }]; + + [_pauseBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(_playBtn); + }]; + + [_currentTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(_separateLabel); + make.leading.equalTo(_playBtn.mas_trailing).offset(-8); + make.width.equalTo(_durationTimeLabel).offset(8); + }]; + + [_separateLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(_playBtn); + make.leading.equalTo(_currentTimeLabel.mas_trailing); + }]; + + [_durationTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.equalTo(_separateLabel.mas_trailing); + make.centerY.equalTo(_separateLabel); + }]; + + [_progressSlider mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.equalTo(_durationTimeLabel.mas_trailing).offset(12); + make.height.centerY.equalTo(_playBtn); + make.trailing.equalTo(_fullBtn.mas_leading).offset(-8); + }]; + + [_fullBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.size.equalTo(_playBtn); + make.centerY.equalTo(_playBtn); + make.trailing.offset(0); + }]; + + [SJUIFactory boundaryProtectedWithView:_fullBtn]; + [SJUIFactory boundaryProtectedWithView:_playBtn]; + [SJUIFactory boundaryProtectedWithView:_durationTimeLabel]; + [SJUIFactory boundaryProtectedWithView:_progressSlider]; +} + +- (UIButton *)playBtn { + if ( _playBtn ) return _playBtn; + _playBtn = [SJUIButtonFactory buttonWithImageName:nil target:self sel:@selector(clickedBtn:) tag:SJLightweightBottomControlViewTag_Play]; + return _playBtn; +} + +- (UIButton *)pauseBtn { + if ( _pauseBtn ) return _pauseBtn; + _pauseBtn = [SJUIButtonFactory buttonWithImageName:nil target:self sel:@selector(clickedBtn:) tag:SJLightweightBottomControlViewTag_Pause]; + return _pauseBtn; +} + +- (SJSlider *)progressSlider { + if ( _progressSlider ) return _progressSlider; + _progressSlider = [SJSlider new]; + _progressSlider.enableBufferProgress = YES; + _progressSlider.delegate = self; + return _progressSlider; +} + +- (void)sliderWillBeginDragging:(SJSlider *)slider { + if ( [self.delegate respondsToSelector:@selector(sliderWillBeginDraggingForBottomView:)] ) { + [self.delegate sliderWillBeginDraggingForBottomView:self]; + } +} + +- (void)sliderDidDrag:(SJSlider *)slider { + if ( [self.delegate respondsToSelector:@selector(bottomView:sliderDidDrag:)] ) { + [self.delegate bottomView:self sliderDidDrag:slider.value]; + } +} + +- (void)sliderDidEndDragging:(SJSlider *)slider { + if ( [self.delegate respondsToSelector:@selector(sliderDidEndDraggingForBottomView:)] ) { + [self.delegate sliderDidEndDraggingForBottomView:self]; + } +} + +- (UIButton *)fullBtn { + if ( _fullBtn ) return _fullBtn; + _fullBtn = [SJUIButtonFactory buttonWithImageName:nil target:self sel:@selector(clickedBtn:) tag:SJLightweightBottomControlViewTag_Full]; + return _fullBtn; +} + +- (UILabel *)separateLabel { + if ( _separateLabel ) return _separateLabel; + _separateLabel = [SJUILabelFactory labelWithText:@"/" textColor:[UIColor whiteColor] alignment:NSTextAlignmentCenter font:[UIFont systemFontOfSize:10]]; + return _separateLabel; +} + +- (UILabel *)durationTimeLabel { + if ( _durationTimeLabel ) return _durationTimeLabel; + _durationTimeLabel = [SJUILabelFactory labelWithText:@"00:00" textColor:[UIColor whiteColor] alignment:NSTextAlignmentLeft font:[UIFont systemFontOfSize:self.separateLabel.font.pointSize + 1]]; + return _durationTimeLabel; +} + +- (UILabel *)currentTimeLabel { + if ( _currentTimeLabel ) return _currentTimeLabel; + _currentTimeLabel = [SJUILabelFactory labelWithText:@"00:00" textColor:[UIColor whiteColor] alignment:NSTextAlignmentRight font:[UIFont systemFontOfSize:self.separateLabel.font.pointSize + 1]]; + return _currentTimeLabel; +} + +#pragma mark - +- (void)_bottomSettingHelper { + __weak typeof(self) _self = self; + self.settingRecroder = [[SJVideoPlayerControlSettingRecorder alloc] initWithSettings:^(SJVideoPlayerSettings * _Nonnull setting) { + __strong typeof(_self) self = _self; + if ( !self ) return; + [self.playBtn setImage:setting.playBtnImage forState:UIControlStateNormal]; + [self.pauseBtn setImage:setting.pauseBtnImage forState:UIControlStateNormal]; + [self.fullBtn setImage:setting.fullBtnImage forState:UIControlStateNormal]; + self.progressSlider.traceImageView.backgroundColor = setting.progress_traceColor; + self.progressSlider.trackImageView.backgroundColor = setting.progress_trackColor; + if ( setting.progress_thumbImage ) { + self.progressSlider.thumbImageView.image = setting.progress_thumbImage; + } + else if ( setting.progress_thumbSize ) { + [self.progressSlider setThumbCornerRadius:setting.progress_thumbSize * 0.5 size:CGSizeMake(setting.progress_thumbSize, setting.progress_thumbSize) thumbBackgroundColor:setting.progress_thumbColor]; + } + self.progressSlider.bufferProgressColor = setting.progress_bufferColor; + self.progressSlider.trackHeight = setting.progress_traceHeight; + }]; +} +@end + diff --git a/SJVideoPlayer/LightweightControlView/SJLightweightCenterControlView.h b/SJVideoPlayer/LightweightControlView/SJLightweightCenterControlView.h new file mode 100644 index 000000000..caa11e011 --- /dev/null +++ b/SJVideoPlayer/LightweightControlView/SJLightweightCenterControlView.h @@ -0,0 +1,37 @@ +// +// SJLightweightCenterControlView.h +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSUInteger, SJVideoPlayerCenterViewTag) { + SJVideoPlayerCenterViewTag_Failed, + SJVideoPlayerCenterViewTag_Replay, +}; + +@protocol SJLightweightCenterControlViewDelegate; + +@interface SJLightweightCenterControlView : UIView + +@property (nonatomic, weak, readwrite, nullable) id delegate; + +- (void)failedState; + +- (void)replayState; + +@end + +@protocol SJLightweightCenterControlViewDelegate + +@optional +- (void)centerControlView:(SJLightweightCenterControlView *)view clickedBtnTag:(SJVideoPlayerCenterViewTag)tag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SJVideoPlayer/LightweightControlView/SJLightweightCenterControlView.m b/SJVideoPlayer/LightweightControlView/SJLightweightCenterControlView.m new file mode 100644 index 000000000..0cb54b5e0 --- /dev/null +++ b/SJVideoPlayer/LightweightControlView/SJLightweightCenterControlView.m @@ -0,0 +1,127 @@ +// +// SJLightweightCenterControlView.m +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import "SJLightweightCenterControlView.h" +#import +#import +#import +#import "UIView+SJVideoPlayerSetting.h" + +@interface SJLightweightCenterControlView () + +@property (nonatomic, strong, readonly) UIButton *failedBtn; +@property (nonatomic, strong, readonly) UIButton *replayBtn; + +@end + +@implementation SJLightweightCenterControlView +@synthesize failedBtn = _failedBtn; +@synthesize replayBtn = _replayBtn; + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if ( !self ) return nil; + [self _centerSetupView]; + [self _centerSettings]; + return self; +} + +- (CGSize)intrinsicContentSize { + CGFloat w = ceil(SJScreen_Min() * 0.382); + return CGSizeMake(w, w); +} + +- (void)clickedBtn:(UIButton *)btn { + if ( ![_delegate respondsToSelector:@selector(centerControlView:clickedBtnTag:)] ) return; + [_delegate centerControlView:self clickedBtnTag:btn.tag]; +} + +- (void)failedState { + self.replayBtn.hidden = YES; + self.failedBtn.hidden = NO; +} + +- (void)replayState { + self.replayBtn.hidden = NO; + self.failedBtn.hidden = YES; +} + +- (void)_centerSetupView { + [self addSubview:self.failedBtn]; + [self addSubview:self.replayBtn]; + [_failedBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.offset(0); + }]; + + [_replayBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.offset(0); + }]; +} + +- (UIButton *)failedBtn { + if ( _failedBtn ) return _failedBtn; + _failedBtn = [SJUIButtonFactory buttonWithImageName:@"" target:self sel:@selector(clickedBtn:) tag:SJVideoPlayerCenterViewTag_Failed]; + return _failedBtn; +} +- (UIButton *)replayBtn { + if ( _replayBtn ) return _replayBtn; + _replayBtn = [SJUIButtonFactory buttonWithImageName:@"" target:self sel:@selector(clickedBtn:) tag:SJVideoPlayerCenterViewTag_Replay]; + _replayBtn.titleLabel.numberOfLines = 0; + return _replayBtn; +} + +- (void)_centerSettings { + __weak typeof(self) _self = self; + self.settingRecroder = [[SJVideoPlayerControlSettingRecorder alloc] initWithSettings:^(SJVideoPlayerSettings * _Nonnull setting) { + __strong typeof(_self) self = _self; + if ( !self ) return; + + [self.replayBtn setAttributedTitle:sj_makeAttributesString(^(SJAttributeWorker * _Nonnull make) { + if ( setting.replayBtnImage ) { + make.insert(setting.replayBtnImage, 0, CGPointZero, setting.replayBtnImage.size); + } + if ( setting.replayBtnImage && 0 != setting.replayBtnTitle.length ) { + make.insertText(@"\n", -1); + } + + if ( 0 != setting.replayBtnTitle.length ) { + make.insert([NSString stringWithFormat:@"%@", setting.replayBtnTitle], -1); + make.lastInserted(^(SJAttributesRangeOperator * _Nonnull lastOperator) { + lastOperator + .font(setting.replayBtnFont) + .textColor(setting.replayBtnTitleColor); + }); + } + make.alignment(NSTextAlignmentCenter).lineSpacing(6); + }) forState:UIControlStateNormal]; + + + [self.failedBtn setAttributedTitle:sj_makeAttributesString(^(SJAttributeWorker * _Nonnull make) { + if ( setting.playFailedBtnImage ) { + make.insert(setting.playFailedBtnImage, 0, CGPointZero, setting.playFailedBtnImage.size); + } + if ( setting.playFailedBtnImage && 0 != setting.playFailedBtnTitle.length ) { + make.insertText(@"\n", -1); + } + + if ( 0 != setting.playFailedBtnTitle.length ) { + make.insert([NSString stringWithFormat:@"%@", setting.playFailedBtnTitle], -1); + make.lastInserted(^(SJAttributesRangeOperator * _Nonnull lastOperator) { + lastOperator + .font(setting.playFailedBtnFont) + .textColor(setting.playFailedBtnTitleColor); + }); + } + make.alignment(NSTextAlignmentCenter).lineSpacing(6); + }) forState:UIControlStateNormal]; + + }]; +} + +@end + diff --git a/SJVideoPlayer/LightweightControlView/SJLightweightLeftControlView.h b/SJVideoPlayer/LightweightControlView/SJLightweightLeftControlView.h new file mode 100644 index 000000000..072f1b023 --- /dev/null +++ b/SJVideoPlayer/LightweightControlView/SJLightweightLeftControlView.h @@ -0,0 +1,35 @@ +// +// SJLightweightLeftControlView.h +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN +typedef NS_ENUM(NSUInteger, SJLightweightLeftControlViewTag) { + SJLightweightLeftControlViewTag_Lock, + SJLightweightLeftControlViewTag_Unlock, +}; + +@protocol SJLightweightLeftControlViewDelegate; + +@interface SJLightweightLeftControlView : UIView + +@property (nonatomic, weak, readwrite, nullable) id delegate; + +@property (nonatomic) BOOL lockState; + +@end + + +@protocol SJLightweightLeftControlViewDelegate + +@optional +- (void)leftControlView:(SJLightweightLeftControlView *)view clickedBtnTag:(SJLightweightLeftControlViewTag)tag; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SJVideoPlayer/LightweightControlView/SJLightweightLeftControlView.m b/SJVideoPlayer/LightweightControlView/SJLightweightLeftControlView.m new file mode 100644 index 000000000..eb06a6f71 --- /dev/null +++ b/SJVideoPlayer/LightweightControlView/SJLightweightLeftControlView.m @@ -0,0 +1,93 @@ +// +// SJLightweightLeftControlView.m +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import "SJLightweightLeftControlView.h" +#import "UIView+SJVideoPlayerSetting.h" +#import +#import + +@interface SJLightweightLeftControlView () + +@property (nonatomic, strong, readonly) UIButton *lockBtn; +@property (nonatomic, strong, readonly) UIButton *unlockBtn; + +@end + +@implementation SJLightweightLeftControlView + +@synthesize lockBtn = _lockBtn; +@synthesize unlockBtn = _unlockBtn; + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if ( !self ) return nil; + [self _leftSetupView]; + [self _leftSettingHelper]; + self.lockState = NO; + return self; +} + +- (CGSize)intrinsicContentSize { + return CGSizeMake(49, 49); +} + +- (void)clickedBtn:(UIButton *)btn { + if ( ![_delegate respondsToSelector:@selector(leftControlView:clickedBtnTag:)] ) return; + [_delegate leftControlView:self clickedBtnTag:btn.tag]; +} + +- (void)setLockState:(BOOL)lockState { + _lockState = lockState; + [UIView animateWithDuration:0.25 animations:^{ + if ( lockState ) { + self.lockBtn.alpha = 1; + self.unlockBtn.alpha = 0.001; + } + else { + self.lockBtn.alpha = 0.001; + self.unlockBtn.alpha = 1; + } + }]; +} + +- (void)_leftSetupView { + [self addSubview:self.lockBtn]; + [self addSubview:self.unlockBtn]; + + [_lockBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(_lockBtn.superview); + }]; + + [_unlockBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(_unlockBtn.superview); + }]; +} + +- (UIButton *)lockBtn { + if ( _lockBtn ) return _lockBtn; + _lockBtn = [SJUIButtonFactory buttonWithImageName:nil target:self sel:@selector(clickedBtn:) tag:SJLightweightLeftControlViewTag_Lock]; + return _lockBtn; +} + +- (UIButton *)unlockBtn { + if ( _unlockBtn ) return _unlockBtn; + _unlockBtn = [SJUIButtonFactory buttonWithImageName:nil target:self sel:@selector(clickedBtn:) tag:SJLightweightLeftControlViewTag_Unlock]; + return _unlockBtn; +} + +#pragma mark - +- (void)_leftSettingHelper { + __weak typeof(self) _self = self; + self.settingRecroder = [[SJVideoPlayerControlSettingRecorder alloc] initWithSettings:^(SJVideoPlayerSettings * _Nonnull setting) { + __strong typeof(_self) self = _self; + if ( !self ) return; + [self.lockBtn setImage:setting.lockBtnImage forState:UIControlStateNormal]; + [self.unlockBtn setImage:setting.unlockBtnImage forState:UIControlStateNormal]; + }]; +} +@end diff --git a/SJVideoPlayer/LightweightControlView/SJLightweightTopControlView.h b/SJVideoPlayer/LightweightControlView/SJLightweightTopControlView.h new file mode 100644 index 000000000..11235c5c2 --- /dev/null +++ b/SJVideoPlayer/LightweightControlView/SJLightweightTopControlView.h @@ -0,0 +1,41 @@ +// +// SJLightweightTopControlView.h +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SJLightweightTopControlModel : NSObject +@property (nonatomic) BOOL alwaysShowTitle; +@property (nonatomic) BOOL isPlayOnScrollView; +@property (nonatomic, copy, nullable) NSString *title; +@end + +@protocol SJLightweightTopControlViewDelegate; + +@interface SJLightweightTopControlView : UIView + +@property (nonatomic, weak, readwrite, nullable) id delegate; + +@property (nonatomic, assign) BOOL isFullscreen; + +@property (nonatomic, strong, readonly) SJLightweightTopControlModel *model; + +- (void)needUpdateTitle; + +@property (nonatomic, strong, readonly) UIButton *backBtn; + +@end + +@protocol SJLightweightTopControlViewDelegate + +@optional +- (void)clickedBackBtnOnTopControlView:(SJLightweightTopControlView *)view; + +@end +NS_ASSUME_NONNULL_END diff --git a/SJVideoPlayer/LightweightControlView/SJLightweightTopControlView.m b/SJVideoPlayer/LightweightControlView/SJLightweightTopControlView.m new file mode 100644 index 000000000..d1d3821e0 --- /dev/null +++ b/SJVideoPlayer/LightweightControlView/SJLightweightTopControlView.m @@ -0,0 +1,158 @@ +// +// SJLightweightTopControlView.m +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import "SJLightweightTopControlView.h" +#import +#import +#import "UIView+SJVideoPlayerSetting.h" +#import + +@interface SJLightweightTopControlView () { + SJLightweightTopControlModel *_model; +} + +@property (nonatomic, strong, readonly) UILabel *titleLabel; +@property (nonatomic, strong, readonly) UIView *itemsContainerView; + +@end + +@implementation SJLightweightTopControlView +@synthesize itemsContainerView = _itemsContainerView; +@synthesize backBtn = _backBtn; +@synthesize titleLabel = _titleLabel; + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if ( !self ) return nil; + [self _topSetupViews]; + [self _topSettingHelper]; + return self; +} + +- (CGSize)intrinsicContentSize { + if ( _isFullscreen ) { + return CGSizeMake(SJScreen_Max(), 72); + } + else { + return CGSizeMake(SJScreen_Min(), 55); + } +} + +- (void)setIsFullscreen:(BOOL)isFullscreen { + if ( isFullscreen == _isFullscreen ) return; + _isFullscreen = isFullscreen; + [self invalidateIntrinsicContentSize]; +} + +- (void)needUpdateTitle { + if ( self.isFullscreen ) { + self.titleLabel.hidden = NO; + } + else { + self.titleLabel.hidden = !self.model.alwaysShowTitle; + } + + if ( !self.titleLabel.hidden ) { + NSAttributedString *attrStr = nil; + if ( 0 != self.model.title.length ) { + attrStr = sj_makeAttributesString(^(SJAttributeWorker * _Nonnull make) { + make.font(self.titleLabel.font).textColor(self.titleLabel.textColor); + make.insert(self.model.title, 0); + make.shadow(CGSizeMake(0.5, 0.5), 1, [UIColor blackColor]); + }); + } + _titleLabel.attributedText = attrStr; + } + + if ( _isFullscreen || !self.model.isPlayOnScrollView ) { + _backBtn.hidden = NO; + [_titleLabel mas_remakeConstraints:^(MASConstraintMaker *make) { + make.leading.equalTo(_backBtn.mas_trailing); + make.centerY.equalTo(_backBtn); + make.trailing.equalTo(_itemsContainerView.mas_leading); + }]; + } + else { + _backBtn.hidden = YES; + [_titleLabel mas_remakeConstraints:^(MASConstraintMaker *make) { + make.leading.offset(16); + make.centerY.equalTo(_backBtn); + make.trailing.offset(-16); + }]; + } +} + +- (void)clickedBtn:(UIButton *)btn { + if ( ![_delegate respondsToSelector:@selector(clickedBackBtnOnTopControlView:)] ) return; + [_delegate clickedBackBtnOnTopControlView:self]; +} + +- (void)_topSetupViews { + + [self addSubview:self.backBtn]; + [self addSubview:self.titleLabel]; + [self addSubview:self.itemsContainerView]; + + [_backBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.size.offset(49); + make.leading.bottom.offset(0); + }]; + + [_titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.equalTo(_backBtn.mas_trailing); + make.centerY.equalTo(_backBtn); + make.trailing.equalTo(_itemsContainerView.mas_leading); + }]; + + [_itemsContainerView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.trailing.bottom.offset(0); + make.width.mas_greaterThanOrEqualTo(8); + }]; + + [SJUIFactory boundaryProtectedWithView:_backBtn]; +} + +- (UIButton *)backBtn { + if ( _backBtn ) return _backBtn; + _backBtn = [SJUIButtonFactory buttonWithImageName:nil target:self sel:@selector(clickedBtn:) tag:0]; + return _backBtn; +} + +- (UILabel *)titleLabel { + if ( _titleLabel ) return _titleLabel; + _titleLabel = [UILabel new]; + return _titleLabel; +} + +#pragma mark - +- (void)_topSettingHelper { + __weak typeof(self) _self = self; + self.settingRecroder = [[SJVideoPlayerControlSettingRecorder alloc] initWithSettings:^(SJVideoPlayerSettings * _Nonnull setting) { + __strong typeof(_self) self = _self; + if ( !self ) return; + [self.backBtn setImage:setting.backBtnImage forState:UIControlStateNormal]; + self.titleLabel.font = setting.titleFont; + self.titleLabel.textColor = setting.titleColor; + if ( 0 != self.model.title.length ) self.titleLabel.text = self.model.title; + }]; +} +- (SJLightweightTopControlModel *)model { + if ( _model ) return _model; + _model = [SJLightweightTopControlModel new]; + return _model; +} +- (UIView *)itemsContainerView { + if ( _itemsContainerView ) return _itemsContainerView; + _itemsContainerView = [UIView new]; + return _itemsContainerView; +} +@end + + +@implementation SJLightweightTopControlModel +@end diff --git a/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_fullscreen@2x.png b/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_fullscreen@2x.png old mode 100755 new mode 100644 index a32cc75f2..741fabe7e Binary files a/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_fullscreen@2x.png and b/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_fullscreen@2x.png differ diff --git a/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_fullscreen@3x.png b/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_fullscreen@3x.png index c908f99db..6542ef657 100755 Binary files a/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_fullscreen@3x.png and b/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_fullscreen@3x.png differ diff --git a/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_shrinkscreen@2x.png b/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_shrinkscreen@2x.png new file mode 100644 index 000000000..ea75f09ca Binary files /dev/null and b/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_shrinkscreen@2x.png differ diff --git a/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_shrinkscreen@3x.png b/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_shrinkscreen@3x.png new file mode 100644 index 000000000..2dcb093c9 Binary files /dev/null and b/SJVideoPlayer/Resource/SJVideoPlayer.bundle/sj_video_player_shrinkscreen@3x.png differ diff --git a/SJVideoPlayer/Resource/SJVideoPlayerAnimationHeader.h b/SJVideoPlayer/Resource/SJVideoPlayerAnimationHeader.h new file mode 100644 index 000000000..bd6e80f8e --- /dev/null +++ b/SJVideoPlayer/Resource/SJVideoPlayerAnimationHeader.h @@ -0,0 +1,15 @@ +// +// SJVideoPlayerAnimationHeader.h +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import + +typedef void(^Block)(void); + +extern NSTimeInterval const CommonAnimaDuration; + +extern void UIView_Animations(NSTimeInterval duration, Block __nullable animations, Block __nullable completion); diff --git a/SJVideoPlayer/Resource/SJVideoPlayerAnimationHeader.m b/SJVideoPlayer/Resource/SJVideoPlayerAnimationHeader.m new file mode 100644 index 000000000..1139b413a --- /dev/null +++ b/SJVideoPlayer/Resource/SJVideoPlayerAnimationHeader.m @@ -0,0 +1,43 @@ +// +// SJVideoPlayerAnimationHeader.m +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import "SJVideoPlayerAnimationHeader.h" +#import + +@interface _SJAnimationContext : NSObject +@property (nonatomic, copy, nullable) Block completion; +- (instancetype)initWithCompletion:(nullable Block)completion; +@end + +@implementation _SJAnimationContext +- (instancetype)initWithCompletion:(nullable Block)completion { + self = [super init]; + if ( !self ) return nil; + _completion = completion; + return self; +} +- (void)dealloc { + if ( _completion ) _completion(); +} +@end + +NSTimeInterval const CommonAnimaDuration = 0.25; + +void UIView_Animations(NSTimeInterval duration, Block __nullable animations, Block __nullable completion) { + if ( completion ) { + _SJAnimationContext *context = [[_SJAnimationContext alloc] initWithCompletion:completion]; + [UIView beginAnimations:nil context:(void *)context]; + [UIView setAnimationDelegate:context]; + } + else { + [UIView beginAnimations:nil context:NULL]; + } + [UIView setAnimationDuration:duration]; + if ( animations ) animations(); + [UIView commitAnimations]; +} diff --git a/SJVideoPlayer/Resource/SJVideoPlayerSettings.h b/SJVideoPlayer/Resource/SJVideoPlayerSettings.h index c78980e82..11b0bf9aa 100755 --- a/SJVideoPlayer/Resource/SJVideoPlayerSettings.h +++ b/SJVideoPlayer/Resource/SJVideoPlayerSettings.h @@ -78,6 +78,7 @@ extern NSNotificationName const SJSettingsPlayerNotification; @property (nonatomic, strong, readwrite) UIImage *playBtnImage; @property (nonatomic, strong, readwrite) UIImage *pauseBtnImage; @property (nonatomic, strong, readwrite) UIImage *fullBtnImage; +@property (nonatomic, strong, readwrite) UIImage *shrinkscreenImage; @property (nonatomic, strong, readwrite) UIImage *moreBtnImage; @property (nonatomic, strong, readwrite) UIImage *lockBtnImage; @property (nonatomic, strong, readwrite) UIImage *unlockBtnImage; diff --git a/SJVideoPlayer/Resource/SJVideoPlayerSettings.m b/SJVideoPlayer/Resource/SJVideoPlayerSettings.m index 846e19951..8a6deafa1 100755 --- a/SJVideoPlayer/Resource/SJVideoPlayerSettings.m +++ b/SJVideoPlayer/Resource/SJVideoPlayerSettings.m @@ -38,6 +38,7 @@ - (void)reset { self.playBtnImage = [SJVideoPlayerResources imageNamed:@"sj_video_player_play"]; self.pauseBtnImage = [SJVideoPlayerResources imageNamed:@"sj_video_player_pause"]; self.fullBtnImage = [SJVideoPlayerResources imageNamed:@"sj_video_player_fullscreen"]; + self.shrinkscreenImage = [SJVideoPlayerResources imageNamed:@"sj_video_player_shrinkscreen"]; self.lockBtnImage = [SJVideoPlayerResources imageNamed:@"sj_video_player_lock"]; self.unlockBtnImage = [SJVideoPlayerResources imageNamed:@"sj_video_player_unlock"]; self.replayBtnImage = [SJVideoPlayerResources imageNamed:@"sj_video_player_replay"]; diff --git a/SJVideoPlayer/SJLightweightControlLayer.h b/SJVideoPlayer/SJLightweightControlLayer.h new file mode 100644 index 000000000..0c206f043 --- /dev/null +++ b/SJVideoPlayer/SJLightweightControlLayer.h @@ -0,0 +1,17 @@ +// +// SJLightweightControlLayer.h +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import +#import + +/** + 轻量级的控制层 + */ +@interface SJLightweightControlLayer : NSObject + +@end diff --git a/SJVideoPlayer/SJLightweightControlLayer.m b/SJVideoPlayer/SJLightweightControlLayer.m new file mode 100644 index 000000000..6a0385bff --- /dev/null +++ b/SJVideoPlayer/SJLightweightControlLayer.m @@ -0,0 +1,641 @@ +// +// SJLightweightControlLayer.m +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import "SJLightweightControlLayer.h" +#import "SJLightweightTopControlView.h" +#import "SJLightweightLeftControlView.h" +#import "SJLightweightBottomControlView.h" +#import "SJLightweightCenterControlView.h" +#import +#import "UIView+SJControlAdd.h" +#import "SJVideoPlayerAnimationHeader.h" +#import "SJVideoPlayerControlMaskView.h" +#import "SJVideoPlayer.h" +#import "SJVideoPlayerDraggingProgressView.h" +#import +#import "UIView+SJVideoPlayerSetting.h" +#import +#import "UIView+SJVideoPlayerSetting.h" +#import +#import + +NS_ASSUME_NONNULL_BEGIN +@interface SJLightweightControlLayer () { + UIView *_controlView; + SJVideoPlayerDraggingProgressView *_draggingProgressView; + SJLoadingView *_loadingView; + SJSlider *_bottomSlider; + UIView *_containerView; + SJTimerControl *_lockStateTappedTimerControl; + SJLightweightCenterControlView *_centerControlView; +} +@property (nonatomic, strong, readonly) UIView *containerView; +@property (nonatomic, strong, readonly) SJLightweightTopControlView *topControlView; +@property (nonatomic, strong, readonly) SJVideoPlayerControlMaskView *topMaskView; +@property (nonatomic, strong, readonly) SJLightweightLeftControlView *leftControlView; +@property (nonatomic, strong, readonly) SJLightweightBottomControlView *bottomControlView; +@property (nonatomic, strong, readonly) SJLightweightCenterControlView *centerControlView; +@property (nonatomic, strong, readonly) SJVideoPlayerControlMaskView *bottomMaskView; +@property (nonatomic, strong, readonly) SJVideoPlayerDraggingProgressView *draggingProgressView; + +@property (nonatomic, strong, nullable) SJVideoPlayer *videoPlayer; +@property (nonatomic, strong, readonly) SJLoadingView *loadingView; +@property (nonatomic, strong, readonly) SJSlider *bottomSlider; +@property (nonatomic, strong, nullable) SJVideoPlayerSettings *settings; +@property (nonatomic, strong, readonly) SJTimerControl *lockStateTappedTimerControl; +@property (nonatomic, strong, readonly) UIButton *backBtn; + +@end + +@implementation SJLightweightControlLayer +@synthesize topMaskView = _topMaskView; +@synthesize bottomMaskView = _bottomMaskView; +@synthesize topControlView = _topControlView; +@synthesize leftControlView = _leftControlView; +@synthesize bottomControlView = _bottomControlView; +@synthesize backBtn = _backBtn; + +- (instancetype)init { + self = [super init]; + if ( !self ) return nil; + [self setupViews]; + [self controlViewLoadSetting]; + return self; +} + +- (BOOL)controlLayerDisappearCondition { + return YES; +} + +- (BOOL)triggerGesturesCondition:(CGPoint)location { + return YES; +} + +- (void)installedControlViewToVideoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer { + _videoPlayer = videoPlayer; +} + +- (void)controlLayerNeedAppear:(nonnull __kindof SJBaseVideoPlayer *)videoPlayer { + UIView_Animations(CommonAnimaDuration, ^{ + + if ( SJVideoPlayerPlayState_PlayFailed == videoPlayer.state ) { + [_centerControlView failedState]; + [_centerControlView appear]; + [_topControlView appear]; + [_leftControlView disappear]; + [_bottomControlView disappear]; + } + else { + [_topControlView appear]; + if ( videoPlayer.isFullScreen ) [_leftControlView appear]; + else [_leftControlView disappear]; + [_bottomControlView appear]; + [_bottomSlider disappear]; + + + // top + if ( videoPlayer.isPlayOnScrollView && !videoPlayer.isFullScreen ) { + if ( videoPlayer.URLAsset.alwaysShowTitle ) [_topControlView appear]; + else [_topControlView disappear]; + } + else [_topControlView appear]; + + [_bottomControlView appear]; + + if ( videoPlayer.isFullScreen ) [_leftControlView appear]; + else [_leftControlView disappear]; // 如果是小屏, 则不显示锁屏按钮 + + [_bottomSlider disappear]; + + if ( videoPlayer.state != SJVideoPlayerPlayState_PlayEnd ) [_centerControlView disappear]; + } + }, nil); +} + +- (void)controlLayerNeedDisappear:(nonnull __kindof SJBaseVideoPlayer *)videoPlayer { + UIView_Animations(CommonAnimaDuration, ^{ + if ( SJVideoPlayerPlayState_PlayFailed != videoPlayer.state ) { + [_topControlView disappear]; + [_bottomControlView disappear]; + if ( !videoPlayer.isLockedScreen ) [_leftControlView disappear]; + else [_leftControlView appear]; + [_bottomSlider appear]; + } + else { + [_topControlView appear]; + [_leftControlView disappear]; + [_bottomControlView disappear]; + } + }, nil); +} + +- (void)videoPlayerWillAppearInScrollView:(SJVideoPlayer *)videoPlayer { + videoPlayer.view.hidden = NO; +} + +- (void)videoPlayerWillDisappearInScrollView:(SJVideoPlayer *)videoPlayer { + [videoPlayer pause]; + videoPlayer.view.hidden = YES; +} + +- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer stateChanged:(SJVideoPlayerPlayState)state { + switch ( state ) { + case SJVideoPlayerPlayState_Unknown: { + [videoPlayer controlLayerNeedDisappear]; + self.topControlView.model.title = nil; + [self.topControlView needUpdateTitle]; + self.bottomSlider.value = 0; + self.bottomControlView.progress = 0; + self.bottomControlView.bufferProgress = 0; + [self.bottomControlView setCurrentTimeStr:@"00:00" totalTimeStr:@"00:00"]; + } + break; + case SJVideoPlayerPlayState_Prepare: { + + } + break; + case SJVideoPlayerPlayState_Paused: + case SJVideoPlayerPlayState_PlayFailed: + case SJVideoPlayerPlayState_PlayEnd: { + self.bottomControlView.stopped = YES; + } + break; + case SJVideoPlayerPlayState_Playing: { + self.bottomControlView.stopped = NO; + } + break; + case SJVideoPlayerPlayState_Buffing: { + if ( self.centerControlView.appearState ) { + UIView_Animations(CommonAnimaDuration, ^{ + [self.centerControlView disappear]; + }, nil); + } + } + break; + } + + if ( SJVideoPlayerPlayState_PlayEnd == state ) { + UIView_Animations(CommonAnimaDuration, ^{ + [self.centerControlView appear]; + [self.centerControlView replayState]; + }, nil); + } +} + +- (void)videoPlayer:(SJVideoPlayer *)videoPlayer prepareToPlay:(SJVideoPlayerURLAsset *)asset { + self.backBtn.hidden = videoPlayer.isPlayOnScrollView; + if ( videoPlayer.isPlayOnScrollView ) { + [_backBtn removeFromSuperview]; + } + else { + if ( !_backBtn.superview ) { + [self.containerView addSubview:self.backBtn]; + [_backBtn mas_remakeConstraints:^(MASConstraintMaker *make) { + make.edges.equalTo(_topControlView.backBtn); + }]; + } + } + self.topControlView.model.isPlayOnScrollView = videoPlayer.isPlayOnScrollView; + self.topControlView.model.alwaysShowTitle = asset.alwaysShowTitle; + self.topControlView.model.title = asset.title; + [self.topControlView needUpdateTitle]; + + self.bottomSlider.value = 0; + self.bottomControlView.progress = 0; + self.bottomControlView.bufferProgress = 0; + [self.bottomControlView setCurrentTimeStr:videoPlayer.currentTimeStr totalTimeStr:videoPlayer.totalTimeStr]; +} + +- (void)videoPlayer:(SJVideoPlayer *)videoPlayer + currentTime:(NSTimeInterval)currentTime currentTimeStr:(NSString *)currentTimeStr + totalTime:(NSTimeInterval)totalTime totalTimeStr:(NSString *)totalTimeStr { + [self.bottomControlView setCurrentTimeStr:currentTimeStr totalTimeStr:totalTimeStr]; + float progress = videoPlayer.progress; + self.bottomSlider.value = progress; + self.bottomControlView.progress = progress; + if ( self.draggingProgressView.appearState ) self.draggingProgressView.playProgress = progress; +} + +- (void)videoPlayer:(SJVideoPlayer *)videoPlayer loadedTimeProgress:(float)progress { + self.bottomControlView.bufferProgress = progress; +} + +- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer willRotateView:(BOOL)isFull { + if ( isFull && !videoPlayer.URLAsset.isM3u8 ) { + _draggingProgressView.style = SJVideoPlayerDraggingProgressViewStylePreviewProgress; + } + else { + _draggingProgressView.style = SJVideoPlayerDraggingProgressViewStyleArrowProgress; + } + + _topControlView.isFullscreen = isFull; + [_topControlView needUpdateTitle]; + + UIView_Animations(CommonAnimaDuration, ^{ + [self.controlView layoutIfNeeded]; + }, nil); + + if ( videoPlayer.controlLayerAppeared ) [videoPlayer controlLayerNeedAppear]; // update + + if ( isFull ) { + // `iPhone_X` remake constraints. + if ( SJ_is_iPhoneX() ) { + [self.containerView mas_remakeConstraints:^(MASConstraintMaker *make) { + make.center.offset(0); + make.height.equalTo(self.containerView.superview); + make.width.equalTo(self.containerView.mas_height).multipliedBy(16 / 9.0f); + }]; + } + } + else { + // `iPhone_X` remake constraints. + if ( SJ_is_iPhoneX() ) { + [self.containerView mas_remakeConstraints:^(MASConstraintMaker *make) { + make.edges.offset(0); + }]; + } + } +} + +- (void)horizontalDirectionWillBeginDragging:(SJVideoPlayer *)videoPlayer { + [self sliderWillBeginDraggingForBottomView:self.bottomControlView]; +} + +- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer horizontalDirectionDidMove:(CGFloat)progress { + [self bottomView:self.bottomControlView sliderDidDrag:progress]; +} + +- (void)horizontalDirectionDidEndDragging:(SJVideoPlayer *)videoPlayer { + [self sliderDidEndDraggingForBottomView:self.bottomControlView]; +} + +- (void)startLoading:(SJVideoPlayer *)videoPlayer { + [self.loadingView start]; +} + +- (void)cancelLoading:(__kindof SJBaseVideoPlayer *)videoPlayer { + [self.loadingView stop]; +} + +- (void)loadCompletion:(SJVideoPlayer *)videoPlayer { + [self.loadingView stop]; +} + +- (void)lockedVideoPlayer:(SJVideoPlayer *)videoPlayer { + _leftControlView.lockState = YES; + [self.lockStateTappedTimerControl start]; + [videoPlayer controlLayerNeedDisappear]; +} + +- (void)unlockedVideoPlayer:(SJVideoPlayer *)videoPlayer { + _leftControlView.lockState = NO; + [self.lockStateTappedTimerControl clear]; + [videoPlayer controlLayerNeedAppear]; +} + +- (void)tappedPlayerOnTheLockedState:(__kindof SJBaseVideoPlayer *)videoPlayer { + UIView_Animations(CommonAnimaDuration, ^{ + if ( _leftControlView.appearState ) [_leftControlView disappear]; + else [_leftControlView appear]; + }, nil); + if ( _leftControlView.appearState ) [_lockStateTappedTimerControl start]; + else [_lockStateTappedTimerControl clear]; +} +#pragma mark - Network +- (void)videoPlayer:(SJBaseVideoPlayer *)videoPlayer reachabilityChanged:(SJNetworkStatus)status { + [self _promptWithNetworkStatus:status]; +} + +- (void)_promptWithNetworkStatus:(SJNetworkStatus)status { + if ( self.videoPlayer.disableNetworkStatusChangePrompt ) return; + if ( [self.videoPlayer.assetURL isFileURL] ) return; // return when is local video. + + switch ( status ) { + case SJNetworkStatus_NotReachable: { + [self.videoPlayer showTitle:self.settings.notReachablePrompt duration:3]; + } + break; + case SJNetworkStatus_ReachableViaWWAN: { + [self.videoPlayer showTitle:self.settings.reachableViaWWANPrompt duration:3]; + } + break; + case SJNetworkStatus_ReachableViaWiFi: { + + } + break; + } +} +#pragma mark - +- (void)setupViews { + [self.controlView addSubview:self.topMaskView]; + [self.controlView addSubview:self.bottomMaskView]; + [self.controlView addSubview:self.containerView]; + + [self.containerView addSubview:self.topControlView]; + [self.containerView addSubview:self.leftControlView]; + [self.containerView addSubview:self.bottomControlView]; + [self.containerView addSubview:self.draggingProgressView]; + [self.containerView addSubview:self.loadingView]; + [self.containerView addSubview:self.bottomSlider]; + [self.containerView addSubview:self.centerControlView]; + + [_topMaskView mas_makeConstraints:^(MASConstraintMaker *make) { + make.height.equalTo(_topControlView); + make.top.leading.trailing.offset(0); + }]; + + [_bottomMaskView mas_makeConstraints:^(MASConstraintMaker *make) { + make.height.equalTo(_bottomControlView); + make.leading.bottom.trailing.offset(0); + }]; + + [_containerView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.offset(0); + }]; + + [_topControlView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.leading.trailing.offset(0); + }]; + + [_leftControlView mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.offset(0); + make.centerY.offset(0); + }]; + + [_bottomControlView mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.bottom.trailing.offset(0); + }]; + + [_draggingProgressView mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.offset(0); + }]; + + [_loadingView mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.offset(0); + }]; + + [_bottomSlider mas_makeConstraints:^(MASConstraintMaker *make) { + make.leading.bottom.trailing.offset(0); + make.height.offset(1); + }]; + + [_centerControlView mas_makeConstraints:^(MASConstraintMaker *make) { + make.center.offset(0); + }]; + + [self _setControlViewsDisappearValue]; + [_topControlView disappear]; + [_leftControlView disappear]; + [_bottomControlView disappear]; + [_draggingProgressView disappear]; + [_centerControlView disappear]; +} + +- (void)_setControlViewsDisappearValue { + _topMaskView.disappearType = SJDisappearType_Alpha; + _topControlView.disappearType = SJDisappearType_Alpha; + _leftControlView.disappearType = SJDisappearType_Alpha; + _bottomMaskView.disappearType = SJDisappearType_Alpha; + _bottomControlView.disappearType = SJDisappearType_Alpha; + _draggingProgressView.disappearType = SJDisappearType_Alpha; + _bottomSlider.disappearType = SJDisappearType_Alpha; + _centerControlView.disappearType = SJDisappearType_Alpha; + + __weak typeof(self) _self = self; + void(^block)(__kindof UIView *view) = ^(__kindof UIView *view) { + __strong typeof(_self) self = _self; + if ( !self ) return; + if ( view == self.topControlView ) { + if ( view.appearState ) [self.topMaskView appear]; + else [self.topMaskView disappear]; + } + else if ( view == self.bottomControlView ) { + if ( view.appearState ) [self.bottomMaskView appear]; + else [self.bottomMaskView disappear]; + } + }; + + _topControlView.appearExeBlock = block; + _topControlView.disappearExeBlock = block; + _bottomControlView.appearExeBlock = block; + _bottomControlView.disappearExeBlock = block; +} + +- (UIView *)controlView { + if ( _controlView ) return _controlView; + _controlView = [UIView new]; + return _controlView; +} +#pragma mark - top control view +- (SJLightweightTopControlView *)topControlView { + if ( _topControlView ) return _topControlView; + _topControlView = [SJLightweightTopControlView new]; + _topControlView.delegate = self; + return _topControlView; +} +- (void)clickedBackBtnOnTopControlView:(SJLightweightTopControlView *)view { + if ( _videoPlayer.isFullScreen ) { + SJSupportedRotateViewOrientation supported = _videoPlayer.supportedRotateViewOrientation; + if ( supported == SJSupportedRotateViewOrientation_All ) { + supported = SJSupportedRotateViewOrientation_Portrait | SJSupportedRotateViewOrientation_LandscapeLeft | SJSupportedRotateViewOrientation_LandscapeRight; + } + if ( SJSupportedRotateViewOrientation_Portrait == (supported & SJSupportedRotateViewOrientation_Portrait) ) { + [_videoPlayer rotation]; + return; + } + } + if ( _videoPlayer.clickedBackEvent ) _videoPlayer.clickedBackEvent(_videoPlayer); +} +- (SJLightweightLeftControlView *)leftControlView { + if ( _leftControlView ) return _leftControlView; + _leftControlView = [SJLightweightLeftControlView new]; + _leftControlView.delegate = self; + return _leftControlView; +} +- (void)leftControlView:(SJLightweightLeftControlView *)view clickedBtnTag:(SJLightweightLeftControlViewTag)tag { + switch ( tag ) { + case SJLightweightLeftControlViewTag_Lock: { + _videoPlayer.lockedScreen = NO; // 点击锁定按钮, 解锁 + } + break; + case SJLightweightLeftControlViewTag_Unlock: { + _videoPlayer.lockedScreen = YES; // 点击解锁按钮, 锁定 + } + break; + } +} +#pragma mark - center view +- (SJLightweightCenterControlView *)centerControlView { + if ( _centerControlView ) return _centerControlView; + _centerControlView = [SJLightweightCenterControlView new]; + _centerControlView.delegate = self; + return _centerControlView; +} + +- (void)centerControlView:(SJLightweightCenterControlView *)view clickedBtnTag:(SJVideoPlayerCenterViewTag)tag { + switch ( tag ) { + case SJVideoPlayerCenterViewTag_Replay: { + [_videoPlayer replay]; + } + break; + case SJVideoPlayerCenterViewTag_Failed: { + [_videoPlayer refresh]; + } + break; + default: + break; + } +} +#pragma mark - bottom control view +- (SJLightweightBottomControlView *)bottomControlView { + if ( _bottomControlView ) return _bottomControlView; + _bottomControlView = [SJLightweightBottomControlView new]; + _bottomControlView.delegate = self; + return _bottomControlView; +} +- (void)bottomControlView:(SJLightweightBottomControlView *)bottomControlView clickedViewTag:(SJLightweightBottomControlViewTag)tag { + switch ( tag ) { + case SJLightweightBottomControlViewTag_Full: { + [_videoPlayer rotation]; + } + break; + case SJLightweightBottomControlViewTag_Play: { + if ( _videoPlayer.state == SJVideoPlayerPlayState_PlayEnd ) [_videoPlayer replay]; + else [_videoPlayer play]; + } + break; + case SJLightweightBottomControlViewTag_Pause: { + [_videoPlayer pauseForUser]; + } + break; + } +} +- (void)sliderWillBeginDraggingForBottomView:(SJLightweightBottomControlView *)view { + UIView_Animations(CommonAnimaDuration, ^{ + [self.draggingProgressView appear]; + }, nil); + [self.draggingProgressView setTimeShiftStr:self.videoPlayer.currentTimeStr totalTimeStr:self.videoPlayer.totalTimeStr]; + [_videoPlayer controlLayerNeedDisappear]; + self.draggingProgressView.playProgress = self.videoPlayer.progress; + self.draggingProgressView.shiftProgress = self.videoPlayer.progress; +} + +- (void)bottomView:(SJLightweightBottomControlView *)view sliderDidDrag:(CGFloat)progress { + self.draggingProgressView.shiftProgress = progress; + [self.draggingProgressView setTimeShiftStr:[self.videoPlayer timeStringWithSeconds:self.draggingProgressView.shiftProgress * self.videoPlayer.totalTime]]; + if ( self.videoPlayer.isFullScreen && !self.videoPlayer.URLAsset.isM3u8 ) { + NSTimeInterval secs = self.draggingProgressView.shiftProgress * self.videoPlayer.totalTime; + __weak typeof(self) _self = self; + [self.videoPlayer screenshotWithTime:secs size:CGSizeMake(self.draggingProgressView.frame.size.width * 2, self.draggingProgressView.frame.size.height * 2) completion:^(SJVideoPlayer * _Nonnull videoPlayer, UIImage * _Nullable image, NSError * _Nullable error) { + __strong typeof(_self) self = _self; + if ( !self ) return; + [self.draggingProgressView setPreviewImage:image]; + }]; + } +} + +- (void)sliderDidEndDraggingForBottomView:(SJLightweightBottomControlView *)view { + UIView_Animations(CommonAnimaDuration, ^{ + [self.draggingProgressView disappear]; + }, nil); + + __weak typeof(self) _self = self; + [self.videoPlayer jumpedToTime:self.draggingProgressView.shiftProgress * self.videoPlayer.totalTime completionHandler:^(BOOL finished) { + __strong typeof(_self) self = _self; + if ( !self ) return; + [self.videoPlayer play]; + }]; +} + +#pragma mark - dragging progress view +- (SJVideoPlayerDraggingProgressView *)draggingProgressView { + if ( _draggingProgressView ) return _draggingProgressView; + _draggingProgressView = [SJVideoPlayerDraggingProgressView new]; + return _draggingProgressView; +} + +#pragma mark - loading view +- (SJLoadingView *)loadingView { + if ( _loadingView ) return _loadingView; + _loadingView = [SJLoadingView new]; + __weak typeof(self) _self = self; + _loadingView.settingRecroder = [[SJVideoPlayerControlSettingRecorder alloc] initWithSettings:^(SJVideoPlayerSettings * _Nonnull setting) { + __strong typeof(_self) self = _self; + if ( !self ) return; + self.loadingView.lineColor = setting.loadingLineColor; + }]; + return _loadingView; +} + +#pragma mark - +- (SJVideoPlayerControlMaskView *)topMaskView { + if ( _topMaskView ) return _topMaskView; + _topMaskView = [[SJVideoPlayerControlMaskView alloc] initWithStyle:SJMaskStyle_top]; + return _topMaskView; +} +- (SJVideoPlayerControlMaskView *)bottomMaskView { + if ( _bottomMaskView ) return _bottomMaskView; + _bottomMaskView = [[SJVideoPlayerControlMaskView alloc] initWithStyle:SJMaskStyle_bottom]; + return _bottomMaskView; +} +- (UIView *)containerView { + if ( _containerView ) return _containerView; + _containerView = [UIView new]; + _containerView.clipsToBounds = YES; + return _containerView; +} +- (UIButton *)backBtn { + if ( _backBtn ) return _backBtn; + _backBtn = [SJUIButtonFactory buttonWithImageName:nil target:self sel:@selector(clickedBtn:) tag:0]; + return _backBtn; +} +- (void)clickedBtn:(UIButton *)btn { + [self clickedBackBtnOnTopControlView:self.topControlView]; +} +- (SJSlider *)bottomSlider { + if ( _bottomSlider ) return _bottomSlider; + _bottomSlider = [SJSlider new]; + _bottomSlider.pan.enabled = NO; + _bottomSlider.trackHeight = 1; + return _bottomSlider; +} +- (void)controlViewLoadSetting { + // load setting + SJVideoPlayer.update(^(SJVideoPlayerSettings * _Nonnull commonSettings) {}); + + __weak typeof(self) _self = self; + self.controlView.settingRecroder = [[SJVideoPlayerControlSettingRecorder alloc] initWithSettings:^(SJVideoPlayerSettings * _Nonnull setting) { + __strong typeof(_self) self = _self; + if ( !self ) return; + [self.backBtn setImage:setting.backBtnImage forState:UIControlStateNormal]; + self.bottomSlider.traceImageView.backgroundColor = setting.progress_traceColor; + self.bottomSlider.trackImageView.backgroundColor = setting.progress_bufferColor; + self.videoPlayer.placeholder = setting.placeholder; + [self.draggingProgressView setPreviewImage:setting.placeholder]; + self.settings = setting; + }]; +} + +#pragma mark - +- (SJTimerControl *)lockStateTappedTimerControl { + if ( _lockStateTappedTimerControl ) return _lockStateTappedTimerControl; + _lockStateTappedTimerControl = [[SJTimerControl alloc] init]; + __weak typeof(self) _self = self; + _lockStateTappedTimerControl.exeBlock = ^(SJTimerControl * _Nonnull control) { + __strong typeof(_self) self = _self; + if ( !self ) return; + [control clear]; + UIView_Animations(CommonAnimaDuration, ^{ + if ( self.leftControlView.appearState ) [self.leftControlView disappear]; + }, nil); + }; + return _lockStateTappedTimerControl; +} +@end + +NS_ASSUME_NONNULL_END diff --git a/SJVideoPlayer/SJVideoPlayer.h b/SJVideoPlayer/SJVideoPlayer.h index 74733fad2..ef06d5cfe 100755 --- a/SJVideoPlayer/SJVideoPlayer.h +++ b/SJVideoPlayer/SJVideoPlayer.h @@ -34,6 +34,33 @@ NS_ASSUME_NONNULL_BEGIN - (instancetype)initWithControlLayerDataSource:(nullable id )controlLayerDataSource controlLayerDelegate:(nullable id)controlLayerDelegate; // 指定控制层 + +/** + A lightweight player with simple functions. + 一个具有简单功能的播放器. + + @return player + */ ++ (instancetype)lightweightPlayer; + + +/** + Clicked back btn exe block. + 点击`返回`按钮的回调. + + readwrite. + */ +@property (nonatomic, copy, readwrite) void(^clickedBackEvent)(SJVideoPlayer *player); + + +/** + If yes, the player will prompt the user when the network status changes. + 是否禁止网络状态变化时的提示, 默认是NO. + + readwrite. + */ +@property (nonatomic) BOOL disableNetworkStatusChangePrompt; // default is NO. 是否禁止网路状态变化提示. 默认为No. + @end @@ -45,21 +72,10 @@ NS_ASSUME_NONNULL_BEGIN * Whether to generate a preview view. default is YES. * * 是否自动生成预览视图, 默认是 YES. 如果为NO, 则预览按钮将不会显示. - */ -@property (nonatomic, assign, readwrite) BOOL generatePreviewImages; - -/** - * clicked back btn exe block. * - * 点击`返回`按钮的回调. - */ -@property (nonatomic, copy, readwrite) void(^clickedBackEvent)(SJVideoPlayer *player); - - -/** - If yes, the player will prompt the user when the network status changes. + * readwrite. */ -@property (nonatomic, assign, readwrite) BOOL disableNetworkStatusChangePrompt; // default is NO. 是否禁止网路状态变化提示. 默认为No. +@property (nonatomic) BOOL generatePreviewImages; /** * Configure the player, Note: T his `block` is run on the child thread. @@ -81,17 +97,23 @@ NS_ASSUME_NONNULL_BEGIN * clicked More button to display items. * * 点击`更多(右上角的三个点)`按钮, 弹出来的选项. + * + * readwrite. **/ -@property (nonatomic, strong, readwrite, nullable) NSArray *moreSettings; - +@property (nonatomic, strong, nullable) NSArray *moreSettings; /** - If yes, the player will display the right control view. - But if the format of the video is m3u8, it does not work. + If yes, the player will display the right control view. + But if the format of the video is m3u8, it does not work. + + readwrite. */ -@property (nonatomic, assign, readwrite) BOOL enableFilmEditing; +@property (nonatomic) BOOL enableFilmEditing; -@property (nonatomic, strong, readwrite, nullable) SJFilmEditingResultShare *filmEditingResultShare; +/** + readwrite. + */ +@property (nonatomic, strong, nullable) SJFilmEditingResultShare *filmEditingResultShare; - (void)exitFilmEditingCompletion:(void(^__nullable)(SJVideoPlayer *player))completion; diff --git a/SJVideoPlayer/SJVideoPlayer.m b/SJVideoPlayer/SJVideoPlayer.m index d8119075f..171ce111e 100644 --- a/SJVideoPlayer/SJVideoPlayer.m +++ b/SJVideoPlayer/SJVideoPlayer.m @@ -9,12 +9,14 @@ #import "SJVideoPlayer.h" #import #import "SJVideoPlayerDefaultControlView.h" +#import "SJLightweightControlLayer.h" #pragma mark - NS_ASSUME_NONNULL_BEGIN -@interface SJVideoPlayer () { +@interface SJVideoPlayer () { SJVideoPlayerDefaultControlView *_defaultControlView; + SJLightweightControlLayer *_lightweightControlLayer; } @property (nonatomic, strong, readonly) SJVideoPlayerDefaultControlView *defaultControlView; @@ -55,7 +57,6 @@ - (instancetype)initWithControlLayerDataSource:(nullable id -@property (nonatomic, weak, readwrite, nullable) id delegate; - @property (nonatomic, strong, readwrite, nullable) NSArray *moreSettings; @property (nonatomic, strong, readwrite, nullable) SJFilmEditingResultShare *filmEditingResultShare; @property (nonatomic, readwrite) BOOL generatePreviewImages; -@property (nonatomic, readwrite) BOOL disableNetworkStatusChangePrompt; // default is no. - @property (nonatomic, readwrite) BOOL enableFilmEditing; - (void)exitFilmEditingCompletion:(void(^ __nullable)(SJVideoPlayerDefaultControlView *view))completion; @end -@protocol SJVideoPlayerDefaultControlViewDelegate - -@required -- (void)clickedBackBtnOnControlView:(SJVideoPlayerDefaultControlView *)controlView; - -@end - NS_ASSUME_NONNULL_END diff --git a/SJVideoPlayer/SJVideoPlayerDefaultControlView.m b/SJVideoPlayer/SJVideoPlayerDefaultControlView.m index dfd2114af..a03852aff 100644 --- a/SJVideoPlayer/SJVideoPlayerDefaultControlView.m +++ b/SJVideoPlayer/SJVideoPlayerDefaultControlView.m @@ -30,19 +30,17 @@ #import "SJVideoPlayerFilmEditingControlView.h" #import "SJVideoPlayerControlMaskView.h" #import +#import "SJVideoPlayerAnimationHeader.h" +#import #pragma mark - NS_ASSUME_NONNULL_BEGIN -typedef void(^Block)(void); - -static NSTimeInterval CommonAnimaDuration = 0.25; - -inline static void UIView_Animations(NSTimeInterval duration, Block __nullable animations, Block __nullable completion); - #pragma mark - -@interface SJVideoPlayerDefaultControlView () +@interface SJVideoPlayerDefaultControlView () { + SJTimerControl *_lockStateTappedTimerControl; +} @property (nonatomic, assign) BOOL hasBeenGeneratedPreviewImages; @property (nonatomic, strong, readonly) SJMoreSettingsSlidersViewModel *footerViewModel; @@ -61,6 +59,7 @@ @interface SJVideoPlayerDefaultControlView () Appear. NO -> Disappear. @@ -616,6 +625,13 @@ typedef NS_ENUM(NSInteger, SJNetworkStatus) { */ - (void)unlockedVideoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer; +#pragma mark - This Tap gesture triggered when player locked screen. + +/** + If player locked(videoPlayer.lockedScreen == YES), When the user tapped on the player this method will be called. + */ +- (void)tappedPlayerOnTheLockedState:(__kindof SJBaseVideoPlayer *)videoPlayer; + #pragma mark - 屏幕旋转 /** Call it when player will rotate the screen, `isFull` if YES, then full screen. @@ -657,7 +673,6 @@ typedef NS_ENUM(NSInteger, SJNetworkStatus) { #pragma mark - Network /// 网络状态变更 - (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer reachabilityChanged:(SJNetworkStatus)status; - @end NS_ASSUME_NONNULL_END diff --git a/SJVideoPlayerProject/Pods/SJBaseVideoPlayer/SJBaseVideoPlayer/SJBaseVideoPlayer.m b/SJVideoPlayerProject/Pods/SJBaseVideoPlayer/SJBaseVideoPlayer/SJBaseVideoPlayer.m index f50b32572..4425db28f 100644 --- a/SJVideoPlayerProject/Pods/SJBaseVideoPlayer/SJBaseVideoPlayer/SJBaseVideoPlayer.m +++ b/SJVideoPlayerProject/Pods/SJBaseVideoPlayer/SJBaseVideoPlayer/SJBaseVideoPlayer.m @@ -39,11 +39,14 @@ - (CGSize)videoPresentationSize { @interface _SJControlLayerAppearStateManager : NSObject @property (nonatomic, getter=isEnabled) BOOL enabled; @property (nonatomic, readonly) BOOL controlLayerAppearedState; +@property (nonatomic, readonly) BOOL initialization; - (instancetype)initWithVideoPlayer:(SJBaseVideoPlayer *)videoPlayer; - (void)considerChangeState; - (void)layerAppear; - (void)layerDisappear; +- (void)resetInitialization; @property (nonatomic) BOOL pausedToKeepAppearState; +@property (nonatomic) BOOL playFailedToKeepAppearState; @end NS_ASSUME_NONNULL_END @@ -73,6 +76,7 @@ @interface SJBaseVideoPlayer () { _SJControlLayerAppearStateManager *_displayRecorder; SJVideoPlayerRegistrar *_registrar; _SJReachabilityObserver *_reachabilityObserver; + UITapGestureRecognizer *_lockStateTapGesture; } @property (nonatomic, assign, readwrite) BOOL userClickedPause; @@ -93,6 +97,8 @@ @interface SJBaseVideoPlayer () { @property (nonatomic, strong, readonly) _SJControlLayerAppearStateManager *displayRecorder; @property (nonatomic, strong, readonly) _SJReachabilityObserver *reachabilityObserver; +@property (nonatomic, strong, readonly) UITapGestureRecognizer *lockStateTapGesture; + - (void)clearAsset; @end @@ -113,6 +119,7 @@ - (instancetype)init { self.autoPlay = YES; self.enableControlLayerDisplayController = YES; self.pauseWhenAppResignActive = YES; + self.playFailedToKeepAppearState = YES; [self registrar]; return self; } @@ -123,7 +130,7 @@ - (void)dealloc { #endif if ( self.asset && self.assetDeallocExeBlock ) self.assetDeallocExeBlock(self); [_presentView removeFromSuperview]; - [self stop]; + [self clearAsset]; } #pragma mark - @@ -138,6 +145,12 @@ - (void)setAsset:(SJVideoPlayerAssetCarrier *)asset { __weak typeof(self) _self = self; + asset.convertToOriginalExeBlock = ^(SJVideoPlayerAssetCarrier * _Nonnull asset) { + __strong typeof(_self) self = _self; + if ( !self ) return; + [self _itemPrepareToPlay]; + }; + asset.loadedPlayerExeBlock = ^(SJVideoPlayerAssetCarrier * _Nonnull asset) { __strong typeof(_self) self = _self; if ( !self ) return; @@ -146,17 +159,50 @@ - (void)setAsset:(SJVideoPlayerAssetCarrier *)asset { if ( asset.loadedPlayer ) asset.loadedPlayerExeBlock(asset); + asset.startBuffering = ^(SJVideoPlayerAssetCarrier * _Nonnull asset) { + __strong typeof(_self) self = _self; + if ( !self ) return; + if ( SJVideoPlayerPlayState_Paused == self.state ) return; + if ( [self.controlLayerDelegate respondsToSelector:@selector(startLoading:)] ) { + [self.controlLayerDelegate startLoading:self]; + } + self.state = SJVideoPlayerPlayState_Buffing; + [self.asset.player pause]; + }; + + asset.cancelledBuffer = ^(SJVideoPlayerAssetCarrier * _Nonnull asset) { + __strong typeof(_self) self = _self; + if ( !self ) return; + if ( [self.controlLayerDelegate respondsToSelector:@selector(cancelLoading:)] ) { + [self.controlLayerDelegate cancelLoading:self]; + } + }; + + asset.completeBuffer = ^(SJVideoPlayerAssetCarrier * _Nonnull asset) { + __strong typeof(_self) self = _self; + if ( !self ) return; + if ( [self.controlLayerDelegate respondsToSelector:@selector(loadCompletion:)] ) { + [self.controlLayerDelegate loadCompletion:self]; + } + if ( SJVideoPlayerPlayState_Paused != self.state ) [self play]; + }; + asset.playerItemStateChanged = ^(SJVideoPlayerAssetCarrier * _Nonnull asset, AVPlayerItemStatus status) { __strong typeof(_self) self = _self; if ( !self ) return; if ( self.state == SJVideoPlayerPlayState_PlayEnd ) return; switch ( status ) { - case AVPlayerItemStatusUnknown: break; + case AVPlayerItemStatusUnknown: { + asset.startBuffering(asset); + } + break; case AVPlayerItemStatusFailed: { + asset.cancelledBuffer(asset); [self _itemPlayFailed]; } break; case AVPlayerItemStatusReadyToPlay: { + asset.completeBuffer(asset); if ( !self.resignActive ) [self _itemReadyToPlay]; } break; @@ -189,34 +235,6 @@ - (void)setAsset:(SJVideoPlayerAssetCarrier *)asset { if ( 0 != asset.loadedTimeProgressValue ) asset.loadedTimeProgress(asset.loadedTimeProgressValue); - asset.startBuffering = ^(SJVideoPlayerAssetCarrier * _Nonnull asset) { - __strong typeof(_self) self = _self; - if ( !self ) return; - if ( SJVideoPlayerPlayState_Paused == self.state ) return; - if ( [self.controlLayerDelegate respondsToSelector:@selector(startLoading:)] ) { - [self.controlLayerDelegate startLoading:self]; - } - self.state = SJVideoPlayerPlayState_Buffing; - [self.asset.player pause]; - }; - - asset.cancelledBuffer = ^(SJVideoPlayerAssetCarrier * _Nonnull asset) { - __strong typeof(_self) self = _self; - if ( !self ) return; - if ( [self.controlLayerDelegate respondsToSelector:@selector(cancelLoading:)] ) { - [self.controlLayerDelegate cancelLoading:self]; - } - }; - - asset.completeBuffer = ^(SJVideoPlayerAssetCarrier * _Nonnull asset) { - __strong typeof(_self) self = _self; - if ( !self ) return; - if ( [self.controlLayerDelegate respondsToSelector:@selector(loadCompletion:)] ) { - [self.controlLayerDelegate loadCompletion:self]; - } - if ( SJVideoPlayerPlayState_Paused != self.state ) [self play]; - }; - asset.rateChanged = ^(SJVideoPlayerAssetCarrier * _Nonnull asset, float rate) { __strong typeof(_self) self = _self; if ( !self ) return; @@ -335,10 +353,6 @@ - (void)setControlLayerDelegate:(id)controlLa if ( [controlLayerDelegate respondsToSelector:@selector(videoPlayer:brightnessChanged:)] ) { [controlLayerDelegate videoPlayer:self brightnessChanged:_volBrigControl.brightness]; } - if ( SJVideoPlayerPlayState_Prepare == self.state && - [controlLayerDelegate respondsToSelector:@selector(startLoading:)] ) { - [controlLayerDelegate startLoading:self]; - } } - (void)setPlaceholder:(UIImage *)placeholder { @@ -360,16 +374,12 @@ - (AVLayerVideoGravity)videoGravity { #pragma mark - - (void)_itemPrepareToPlay { + self.userClickedPause = NO; + self.state = SJVideoPlayerPlayState_Prepare; + if ( [self.controlLayerDelegate respondsToSelector:@selector(videoPlayer:prepareToPlay:)] ) { [self.controlLayerDelegate videoPlayer:self prepareToPlay:self.URLAsset]; } - - if ( self.autoPlay && [self.controlLayerDelegate respondsToSelector:@selector(startLoading:)] ) { - [self.controlLayerDelegate startLoading:self]; - } - - self.userClickedPause = NO; - self.state = SJVideoPlayerPlayState_Prepare; } - (void)_itemPlayFailed { @@ -392,11 +402,12 @@ - (void)_itemReadyToPlay { [self.controlLayerDelegate loadCompletion:self]; } + [self.displayRecorder resetInitialization]; __weak typeof(self) _self = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ __strong typeof(_self) self = _self; if ( !self ) return; - [self controlLayerNeedAppear]; + if ( !self.displayRecorder.initialization && !self.displayRecorder.controlLayerAppearedState ) [self controlLayerNeedAppear]; }); } @@ -778,6 +789,7 @@ - (_SJReachabilityObserver *)reachabilityObserver { #pragma mark - - (void)setState:(SJVideoPlayerPlayState)state { + if ( state == _state ) return; _state = state; #if 0 switch ( state ) { @@ -829,6 +841,17 @@ - (void)clearAsset { self.asset = nil; } +- (UITapGestureRecognizer *)lockStateTapGesture { + if ( _lockStateTapGesture ) return _lockStateTapGesture; + _lockStateTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleLockStateTapGesture:)]; + return _lockStateTapGesture; +} + +- (void)handleLockStateTapGesture:(UITapGestureRecognizer *)tap { + if ( [self.controlLayerDelegate respondsToSelector:@selector(tappedPlayerOnTheLockedState:)] ) { + [self.controlLayerDelegate tappedPlayerOnTheLockedState:self]; + } +} @end @@ -865,7 +888,7 @@ - (void)playWithURL:(NSURL *)playURL jumpedToTime:(NSTimeInterval)time { - (void)refresh { if ( !self.asset ) return; - self.state = SJVideoPlayerPlayState_Buffing; + self.asset.startBuffering(self.asset); __weak typeof(self) _self = self; dispatch_async(dispatch_get_global_queue(0, 0), ^{ __strong typeof(_self) self = _self; @@ -933,16 +956,13 @@ - (void)jumpedToTime:(NSTimeInterval)time completionHandler:(void (^)(BOOL))comp - (void)seekToTime:(CMTime)time completionHandler:(void (^ __nullable)(BOOL finished))completionHandler { self.state = SJVideoPlayerPlayState_Buffing; - if ( [self.controlLayerDelegate respondsToSelector:@selector(startLoading:)] ) { - [self.controlLayerDelegate startLoading:self]; - } + self.asset.startBuffering(self.asset); __weak typeof(self) _self = self; [self.asset seekToTime:time completionHandler:^(BOOL finished) { __strong typeof(_self) self = _self; if ( !self ) return; - if ( [self.controlLayerDelegate respondsToSelector:@selector(loadCompletion:)] ) { - [self.controlLayerDelegate loadCompletion:self]; - } + if ( finished ) self.asset.completeBuffer(self.asset); + else self.asset.cancelledBuffer(self.asset); if ( completionHandler ) completionHandler(finished); }]; } @@ -977,6 +997,12 @@ - (void)pauseForUser { - (void)setLockedScreen:(BOOL)lockedScreen { objc_setAssociatedObject(self, @selector(isLockedScreen), @(lockedScreen), OBJC_ASSOCIATION_RETAIN_NONATOMIC); + if ( lockedScreen ) { + [self.controlLayerDataSource.controlView addGestureRecognizer:self.lockStateTapGesture]; + } + else { + [self.controlLayerDataSource.controlView removeGestureRecognizer:self.lockStateTapGesture]; + } if ( lockedScreen && [self.controlLayerDelegate respondsToSelector:@selector(lockedVideoPlayer:)] ) { [self.controlLayerDelegate lockedVideoPlayer:self]; } @@ -1006,6 +1032,9 @@ - (BOOL)pauseWhenAppResignActive { } - (BOOL)play { + if ( self.state == SJVideoPlayerPlayState_PlayFailed || + self.state == SJVideoPlayerPlayState_Unknown ) return NO; + self.suspend = NO; self.userClickedPause = NO; @@ -1016,6 +1045,9 @@ - (BOOL)play { } - (BOOL)pause { + if ( self.state == SJVideoPlayerPlayState_PlayFailed || + self.state == SJVideoPlayerPlayState_Unknown ) return NO; + self.suspend = YES; self.userClickedPause = NO; @@ -1185,6 +1217,12 @@ - (void)setPausedToKeepAppearState:(BOOL)pausedToKeepAppearState { - (BOOL)pausedToKeepAppearState { return self.displayRecorder.pausedToKeepAppearState; } +- (void)setPlayFailedToKeepAppearState:(BOOL)playFailedToKeepAppearState { + self.displayRecorder.playFailedToKeepAppearState = playFailedToKeepAppearState; +} +- (BOOL)playFailedToKeepAppearState { + return self.displayRecorder.playFailedToKeepAppearState; +} @end @@ -1431,6 +1469,7 @@ - (instancetype)initWithVideoPlayer:(SJBaseVideoPlayer *)videoPlayer { if ( !self ) return nil; _videoPlayer = videoPlayer; [_videoPlayer sj_addObserver:self forKeyPath:@"locked"]; + [_videoPlayer sj_addObserver:self forKeyPath:@"state"]; return self; } @@ -1443,6 +1482,11 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N [self.controlHiddenTimer start]; } } + else if ( [keyPath isEqualToString:@"state"] ) { + if ( _videoPlayer.state == SJVideoPlayerPlayState_PlayFailed ) { + [self layerAppear]; + } + } } - (void)setEnabled:(BOOL)enabled { @@ -1452,14 +1496,17 @@ - (void)setEnabled:(BOOL)enabled { } - (void)considerChangeState { + if ( _playFailedToKeepAppearState && self.videoPlayer.state == SJVideoPlayerPlayState_PlayFailed ) return; if ( self.controlLayerAppearedState ) [self layerDisappear]; else [self layerAppear]; } - (void)layerAppear { if ( _pausedToKeepAppearState && self.videoPlayer.state == SJVideoPlayerPlayState_Paused ) [self.controlHiddenTimer clear]; + else if ( _playFailedToKeepAppearState && self.videoPlayer.state == SJVideoPlayerPlayState_PlayFailed ) [self.controlHiddenTimer clear]; else [self.controlHiddenTimer start]; [self _changing:YES]; + _initialization = YES; } - (void)layerDisappear { @@ -1467,6 +1514,10 @@ - (void)layerDisappear { [self _changing:NO]; } +- (void)resetInitialization { + _initialization = NO; +} + - (SJTimerControl *)controlHiddenTimer { if ( _controlHiddenTimer ) return _controlHiddenTimer; _controlHiddenTimer = [[SJTimerControl alloc] init]; diff --git a/SJVideoPlayerProject/Pods/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier.h b/SJVideoPlayerProject/Pods/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier.h index 65e28ea72..0adb17e1f 100644 --- a/SJVideoPlayerProject/Pods/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier.h +++ b/SJVideoPlayerProject/Pods/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier.h @@ -229,6 +229,7 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark - other - (NSString *)timeString:(NSInteger)secs; +@property (nonatomic, copy, readwrite, nullable) void(^convertToOriginalExeBlock)(SJVideoPlayerAssetCarrier *asset); @property (nonatomic, copy, readwrite, nullable) void(^deallocExeBlock)(SJVideoPlayerAssetCarrier *asset); diff --git a/SJVideoPlayerProject/Pods/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier.m b/SJVideoPlayerProject/Pods/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier.m index 0a1018eba..9bcc57f8f 100644 --- a/SJVideoPlayerProject/Pods/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier.m +++ b/SJVideoPlayerProject/Pods/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier/SJVideoPlayerAssetCarrier.m @@ -275,7 +275,6 @@ - (void)_clearAVPlayer { [[NSNotificationCenter defaultCenter] removeObserver:_itemEndObserver name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem]; _itemEndObserver = nil; _beginBuffer = NO; [self _cleanBufferTimer]; - if ( _cancelledBuffer ) _cancelledBuffer(self); [_exportSession cancelExport]; _exportSession = nil; _loadedPlayer = NO; @@ -824,6 +823,7 @@ - (void)convertToOriginal { _rateChanged = _ectype.rateChanged; }]; _converted = NO; + if ( _convertToOriginalExeBlock ) _convertToOriginalExeBlock(self); } - (void)_clearUIKit { @@ -923,7 +923,7 @@ - (void)convertToCellWithIndexPath:(NSIndexPath *)indexPath - (void)_convertingWithBlock:(void(^)(void))block { [self _clearUIKit]; if ( block ) block(); - [self _scrollViewObserving]; + [self _scrollViewObserving]; _converted = YES; } @end diff --git a/SJVideoPlayerProject/SJVideoPlayerProject.xcodeproj/project.pbxproj b/SJVideoPlayerProject/SJVideoPlayerProject.xcodeproj/project.pbxproj index 4e366f15c..8b8f1a125 100755 --- a/SJVideoPlayerProject/SJVideoPlayerProject.xcodeproj/project.pbxproj +++ b/SJVideoPlayerProject/SJVideoPlayerProject.xcodeproj/project.pbxproj @@ -10,6 +10,8 @@ 77033C14204E7611008F1ED5 /* DemoPlayerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 77033C13204E7611008F1ED5 /* DemoPlayerViewController.m */; }; 7706E1231FF74B24006E0B56 /* loading.gif in Resources */ = {isa = PBXBuildFile; fileRef = 7706E1221FF74B24006E0B56 /* loading.gif */; }; 7706E1251FF74C42006E0B56 /* slider.gif in Resources */ = {isa = PBXBuildFile; fileRef = 7706E1241FF74C42006E0B56 /* slider.gif */; }; + 7706FC8C20628BC3006A828B /* SJLightweightCenterControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7706FC8B20628BC3006A828B /* SJLightweightCenterControlView.m */; }; + 7706FC932062A96E006A828B /* LightweightViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7706FC922062A96E006A828B /* LightweightViewController.m */; }; 77154E822050D040009E51D7 /* SJVideoPlayerRightControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 77154E812050D040009E51D7 /* SJVideoPlayerRightControlView.m */; }; 77154E8E205255C8009E51D7 /* SJVideoPlayerFilmEditingControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 77154E8D205255C8009E51D7 /* SJVideoPlayerFilmEditingControlView.m */; }; 77154E9120526391009E51D7 /* SJVideoPlayerFilmEditingResultView.m in Sources */ = {isa = PBXBuildFile; fileRef = 77154E9020526391009E51D7 /* SJVideoPlayerFilmEditingResultView.m */; }; @@ -49,6 +51,11 @@ 7790AC7620594B3E00F8DF48 /* SJVideoPlayerMoreSettingsFooterView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7790AC7420594B3E00F8DF48 /* SJVideoPlayerMoreSettingsFooterView.m */; }; 7790AC7A205A58BF00F8DF48 /* AboutKeyboardViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7790AC79205A58BF00F8DF48 /* AboutKeyboardViewController.m */; }; 779A4E6720622C6B0041D8BE /* YYTapActionLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 779A4E6620622C6B0041D8BE /* YYTapActionLabel.m */; }; + 779A4E6D20624E370041D8BE /* SJLightweightControlLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 779A4E6C20624E370041D8BE /* SJLightweightControlLayer.m */; }; + 779A4E7120624F430041D8BE /* SJLightweightTopControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 779A4E7020624F430041D8BE /* SJLightweightTopControlView.m */; }; + 779A4E7420624F580041D8BE /* SJLightweightBottomControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 779A4E7320624F580041D8BE /* SJLightweightBottomControlView.m */; }; + 779A4E7720624F620041D8BE /* SJLightweightLeftControlView.m in Sources */ = {isa = PBXBuildFile; fileRef = 779A4E7620624F620041D8BE /* SJLightweightLeftControlView.m */; }; + 779A4E7D2062568C0041D8BE /* SJVideoPlayerAnimationHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 779A4E7C2062568C0041D8BE /* SJVideoPlayerAnimationHeader.m */; }; 77A47E8F2008DEBE001EBE14 /* nested.gif in Resources */ = {isa = PBXBuildFile; fileRef = 77A47E8B2008DEBE001EBE14 /* nested.gif */; }; 77DA95162042B8EC007A9EE8 /* SJVideoPlayerHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 77DA95142042B8EB007A9EE8 /* SJVideoPlayerHelper.m */; }; 77DA951E2042C04B007A9EE8 /* TestPageViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 77DA95192042C04A007A9EE8 /* TestPageViewController.m */; }; @@ -93,6 +100,10 @@ 77033C13204E7611008F1ED5 /* DemoPlayerViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DemoPlayerViewController.m; sourceTree = ""; }; 7706E1221FF74B24006E0B56 /* loading.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = loading.gif; sourceTree = ""; }; 7706E1241FF74C42006E0B56 /* slider.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = slider.gif; sourceTree = ""; }; + 7706FC8A20628BC3006A828B /* SJLightweightCenterControlView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SJLightweightCenterControlView.h; sourceTree = ""; }; + 7706FC8B20628BC3006A828B /* SJLightweightCenterControlView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJLightweightCenterControlView.m; sourceTree = ""; }; + 7706FC912062A96E006A828B /* LightweightViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LightweightViewController.h; sourceTree = ""; }; + 7706FC922062A96E006A828B /* LightweightViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LightweightViewController.m; sourceTree = ""; }; 77154E802050D040009E51D7 /* SJVideoPlayerRightControlView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SJVideoPlayerRightControlView.h; sourceTree = ""; }; 77154E812050D040009E51D7 /* SJVideoPlayerRightControlView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJVideoPlayerRightControlView.m; sourceTree = ""; }; 77154E8C205255C8009E51D7 /* SJVideoPlayerFilmEditingControlView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SJVideoPlayerFilmEditingControlView.h; sourceTree = ""; }; @@ -162,6 +173,16 @@ 7790AC79205A58BF00F8DF48 /* AboutKeyboardViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AboutKeyboardViewController.m; sourceTree = ""; }; 779A4E6520622C6B0041D8BE /* YYTapActionLabel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YYTapActionLabel.h; sourceTree = ""; }; 779A4E6620622C6B0041D8BE /* YYTapActionLabel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YYTapActionLabel.m; sourceTree = ""; }; + 779A4E6B20624E360041D8BE /* SJLightweightControlLayer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SJLightweightControlLayer.h; sourceTree = ""; }; + 779A4E6C20624E370041D8BE /* SJLightweightControlLayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJLightweightControlLayer.m; sourceTree = ""; }; + 779A4E6F20624F430041D8BE /* SJLightweightTopControlView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SJLightweightTopControlView.h; sourceTree = ""; }; + 779A4E7020624F430041D8BE /* SJLightweightTopControlView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJLightweightTopControlView.m; sourceTree = ""; }; + 779A4E7220624F580041D8BE /* SJLightweightBottomControlView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SJLightweightBottomControlView.h; sourceTree = ""; }; + 779A4E7320624F580041D8BE /* SJLightweightBottomControlView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJLightweightBottomControlView.m; sourceTree = ""; }; + 779A4E7520624F620041D8BE /* SJLightweightLeftControlView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SJLightweightLeftControlView.h; sourceTree = ""; }; + 779A4E7620624F620041D8BE /* SJLightweightLeftControlView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJLightweightLeftControlView.m; sourceTree = ""; }; + 779A4E7B2062568C0041D8BE /* SJVideoPlayerAnimationHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SJVideoPlayerAnimationHeader.h; sourceTree = ""; }; + 779A4E7C2062568C0041D8BE /* SJVideoPlayerAnimationHeader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SJVideoPlayerAnimationHeader.m; sourceTree = ""; }; 77A47E8B2008DEBE001EBE14 /* nested.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = nested.gif; sourceTree = ""; }; 77DA95142042B8EB007A9EE8 /* SJVideoPlayerHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SJVideoPlayerHelper.m; sourceTree = ""; }; 77DA95152042B8EC007A9EE8 /* SJVideoPlayerHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SJVideoPlayerHelper.h; sourceTree = ""; }; @@ -272,6 +293,15 @@ path = ViewController; sourceTree = ""; }; + 7706FC8D2062A818006A828B /* Lightweight_轻量级播放器 */ = { + isa = PBXGroup; + children = ( + 7706FC912062A96E006A828B /* LightweightViewController.h */, + 7706FC922062A96E006A828B /* LightweightViewController.m */, + ); + path = "Lightweight_轻量级播放器"; + sourceTree = ""; + }; 7720056F2029B5C0009F0190 /* Model */ = { isa = PBXGroup; children = ( @@ -442,6 +472,8 @@ 775C0AC120295C660008EDA7 /* SJVideoPlayerResources.m */, 775C0AC220295C660008EDA7 /* SJVideoPlayerSettings.h */, 775C0AC320295C660008EDA7 /* SJVideoPlayerSettings.m */, + 779A4E7B2062568C0041D8BE /* SJVideoPlayerAnimationHeader.h */, + 779A4E7C2062568C0041D8BE /* SJVideoPlayerAnimationHeader.m */, 775C0AC420295C660008EDA7 /* UIView+SJVideoPlayerSetting.h */, 775C0AC520295C660008EDA7 /* UIView+SJVideoPlayerSetting.m */, ); @@ -524,6 +556,21 @@ path = AboutKeyboard; sourceTree = ""; }; + 779A4E6E20624EF50041D8BE /* LightweightControlView */ = { + isa = PBXGroup; + children = ( + 779A4E6F20624F430041D8BE /* SJLightweightTopControlView.h */, + 779A4E7020624F430041D8BE /* SJLightweightTopControlView.m */, + 779A4E7220624F580041D8BE /* SJLightweightBottomControlView.h */, + 779A4E7320624F580041D8BE /* SJLightweightBottomControlView.m */, + 779A4E7520624F620041D8BE /* SJLightweightLeftControlView.h */, + 779A4E7620624F620041D8BE /* SJLightweightLeftControlView.m */, + 7706FC8A20628BC3006A828B /* SJLightweightCenterControlView.h */, + 7706FC8B20628BC3006A828B /* SJLightweightCenterControlView.m */, + ); + path = LightweightControlView; + sourceTree = ""; + }; 77C11C8520295C1900228199 /* DraggingProgress */ = { isa = PBXGroup; children = ( @@ -570,6 +617,7 @@ A644109B200A7289006FD832 /* OtherDemo */, 77033C11204E75F3008F1ED5 /* ViewController */, 773AFC71205D06DE003B2CAC /* Download_下载 */, + 7706FC8D2062A818006A828B /* Lightweight_轻量级播放器 */, ); path = Demo; sourceTree = ""; @@ -632,9 +680,12 @@ A6E6D3492028BE9B00CB9BAE /* SJVideoPlayer.m */, 775C0AD5202962180008EDA7 /* SJVideoPlayerDefaultControlView.h */, 775C0AD6202962180008EDA7 /* SJVideoPlayerDefaultControlView.m */, + 779A4E6B20624E360041D8BE /* SJLightweightControlLayer.h */, + 779A4E6C20624E370041D8BE /* SJLightweightControlLayer.m */, 775C0ABE20295C660008EDA7 /* Resource */, A6E6D3242028BE9B00CB9BAE /* MoreSetting */, A6E6D2FE2028BE9B00CB9BAE /* ControlView */, + 779A4E6E20624EF50041D8BE /* LightweightControlView */, ); name = SJVideoPlayer; path = ../../SJVideoPlayer; @@ -837,7 +888,10 @@ A6E6D3622028BE9B00CB9BAE /* SJVideoPlayerMoreSettingsView.m in Sources */, A6E6D35F2028BE9B00CB9BAE /* SJMoreSettingsSlidersViewModel.m in Sources */, A6E6D3542028BE9B00CB9BAE /* SJVideoPlayerPreviewCollectionViewCell.m in Sources */, + 779A4E7720624F620041D8BE /* SJLightweightLeftControlView.m in Sources */, + 779A4E7420624F580041D8BE /* SJLightweightBottomControlView.m in Sources */, A6F4E9772007A13C00716B9C /* PlayerCollectionViewCell.m in Sources */, + 779A4E7120624F430041D8BE /* SJLightweightTopControlView.m in Sources */, 775B201C2046682E00264AB9 /* TableHeaderCollectionViewCell.m in Sources */, 773AFC64205BA7C1003B2CAC /* DowloadViewController.m in Sources */, A6E6D3632028BE9B00CB9BAE /* SJVideoPlayerMoreSettingsSlidersView.m in Sources */, @@ -855,6 +909,7 @@ 773AFC6D205BCD9E003B2CAC /* SJVideo.m in Sources */, 77DA951E2042C04B007A9EE8 /* TestPageViewController.m in Sources */, A6E6D3582028BE9B00CB9BAE /* SJVideoPlayerCenterControlView.m in Sources */, + 779A4E7D2062568C0041D8BE /* SJVideoPlayerAnimationHeader.m in Sources */, A6E6D3602028BE9B00CB9BAE /* SJVideoPlayerMoreSetting.m in Sources */, 775B200E20455A2800264AB9 /* TableHeaderView.m in Sources */, A6E6D3642028BE9B00CB9BAE /* SJVideoPlayerMoreSettingsColCell.m in Sources */, @@ -872,6 +927,7 @@ 775C0AC720295C660008EDA7 /* SJVideoPlayerResources.m in Sources */, A6E6D3672028BE9B00CB9BAE /* SJVideoPlayerMoreSettingSecondaryView.m in Sources */, A6E6D3552028BE9B00CB9BAE /* SJVideoPlayerTopControlView.m in Sources */, + 779A4E6D20624E370041D8BE /* SJLightweightControlLayer.m in Sources */, 77F4EFFA204029E3004748F6 /* SJSharedVideoPlayerHelper.m in Sources */, 774B252B1FCEBA5D002113CC /* main.m in Sources */, 772005772029BBC7009F0190 /* SJMoreSettingItems.m in Sources */, @@ -881,10 +937,12 @@ 775C0AD7202962180008EDA7 /* SJVideoPlayerDefaultControlView.m in Sources */, 773AFC67205BA86F003B2CAC /* DownloadTableViewCell.m in Sources */, 775B201620465D6200264AB9 /* TableViewHeaderIsCollectionViewDemoViewController.m in Sources */, + 7706FC932062A96E006A828B /* LightweightViewController.m in Sources */, 775B1FFF204555B200264AB9 /* TableViewHeaderDemoViewController.m in Sources */, A6441098200A406E006FD832 /* SJVideoModel.m in Sources */, 774B25571FCED47B002113CC /* PlayerViewController.m in Sources */, 77E754362040056F00A5AF44 /* FullViewController.m in Sources */, + 7706FC8C20628BC3006A828B /* SJLightweightCenterControlView.m in Sources */, 77154E8E205255C8009E51D7 /* SJVideoPlayerFilmEditingControlView.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/SJVideoPlayerProject/SJVideoPlayerProject.xcworkspace/xcuserdata/bluedancer.xcuserdatad/UserInterfaceState.xcuserstate b/SJVideoPlayerProject/SJVideoPlayerProject.xcworkspace/xcuserdata/bluedancer.xcuserdatad/UserInterfaceState.xcuserstate index 249034ecc..d2ba917f9 100755 Binary files a/SJVideoPlayerProject/SJVideoPlayerProject.xcworkspace/xcuserdata/bluedancer.xcuserdatad/UserInterfaceState.xcuserstate and b/SJVideoPlayerProject/SJVideoPlayerProject.xcworkspace/xcuserdata/bluedancer.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/AppDelegate.m b/SJVideoPlayerProject/SJVideoPlayerProject/AppDelegate.m index e1585e838..a02e342b7 100755 --- a/SJVideoPlayerProject/SJVideoPlayerProject/AppDelegate.m +++ b/SJVideoPlayerProject/SJVideoPlayerProject/AppDelegate.m @@ -31,6 +31,7 @@ - (void)_settingVideoPlayer { commonSettings.more_trackColor = [UIColor whiteColor]; commonSettings.progress_trackColor = [UIColor colorWithWhite:0.4 alpha:1]; commonSettings.progress_bufferColor = [UIColor whiteColor]; + commonSettings.progress_thumbSize = 12; }); } diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/Base.lproj/Main.storyboard b/SJVideoPlayerProject/SJVideoPlayerProject/Base.lproj/Main.storyboard index d044f0fd8..524bc2146 100755 --- a/SJVideoPlayerProject/SJVideoPlayerProject/Base.lproj/Main.storyboard +++ b/SJVideoPlayerProject/SJVideoPlayerProject/Base.lproj/Main.storyboard @@ -75,33 +75,42 @@ + + + + - + - diff --git "a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/Lightweight_\350\275\273\351\207\217\347\272\247\346\222\255\346\224\276\345\231\250/LightweightViewController.h" "b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/Lightweight_\350\275\273\351\207\217\347\272\247\346\222\255\346\224\276\345\231\250/LightweightViewController.h" new file mode 100644 index 000000000..df56a0eba --- /dev/null +++ "b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/Lightweight_\350\275\273\351\207\217\347\272\247\346\222\255\346\224\276\345\231\250/LightweightViewController.h" @@ -0,0 +1,13 @@ +// +// LightweightViewController.h +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import + +@interface LightweightViewController : UIViewController + +@end diff --git "a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/Lightweight_\350\275\273\351\207\217\347\272\247\346\222\255\346\224\276\345\231\250/LightweightViewController.m" "b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/Lightweight_\350\275\273\351\207\217\347\272\247\346\222\255\346\224\276\345\231\250/LightweightViewController.m" new file mode 100644 index 000000000..6b8fc89ce --- /dev/null +++ "b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/Lightweight_\350\275\273\351\207\217\347\272\247\346\222\255\346\224\276\345\231\250/LightweightViewController.m" @@ -0,0 +1,188 @@ +// +// LightweightViewController.m +// SJVideoPlayerProject +// +// Created by BlueDancer on 2018/3/21. +// Copyright © 2018年 SanJiang. All rights reserved. +// + +#import "LightweightViewController.h" +#import +#import +#import "SJVideoListTableViewCell.h" +#import "SJVideoModel.h" +#import "SJVideoPlayer.h" +#import "SJVideoPlayerHelper.h" +#import +#import "DemoPlayerViewController.h" +#import "YYTapActionLabel.h" + +static NSString *const SJVideoListTableViewCellID = @"SJVideoListTableViewCell"; + +@interface LightweightViewController () + +@property (nonatomic, strong, readonly) SJVideoPlayerHelper *videoPlayerHelper; +@property (nonatomic, strong, readonly) UIActivityIndicatorView *indicator; +@property (nonatomic, strong, readonly) UITableView *tableView; +@property (nonatomic, strong) NSIndexPath *playedIndexPath; +@property (nonatomic, strong) NSArray *videos; + +@end + +@implementation LightweightViewController + +@synthesize indicator = _indicator; +@synthesize tableView = _tableView; + +- (void)dealloc { + NSLog(@"%zd - %s", __LINE__, __func__); +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + // setup views + [self _videoListSetupViews]; + + [self.indicator startAnimating]; + // prepare test data. + self.tableView.alpha = 0.001; + __weak typeof(self) _self = self; + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + // some test data + NSArray *videos = [SJVideoModel videoModelsWithTapActionDelegate:self]; + dispatch_async(dispatch_get_main_queue(), ^{ + __strong typeof(_self) self = _self; + if ( !self ) return; + self.videos = videos; + [self.tableView reloadData]; + [self.indicator stopAnimating]; + [UIView animateWithDuration:0.3 animations:^{ + self.tableView.alpha = 1; + }]; + }); + }); + + // Do any additional setup after loading the view. +} + +// please lazy load +@synthesize videoPlayerHelper = _videoPlayerHelper; +- (SJVideoPlayerHelper *)videoPlayerHelper { + if ( _videoPlayerHelper ) return _videoPlayerHelper; + _videoPlayerHelper = [[SJVideoPlayerHelper alloc] initWithViewController:self playerType:SJVideoPlayerType_Lightweight]; + return _videoPlayerHelper; +} + +- (BOOL)needConvertAsset { + return NO; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + self.videoPlayerHelper.vc_viewDidAppearExeBlock(); +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + self.videoPlayerHelper.vc_viewWillDisappearExeBlock(); +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; + self.videoPlayerHelper.vc_viewDidDisappearExeBlock(); +} + +- (BOOL)prefersStatusBarHidden { + return self.videoPlayerHelper.vc_prefersStatusBarHiddenExeBlock(); +} + +- (UIStatusBarStyle)preferredStatusBarStyle { + return self.videoPlayerHelper.vc_preferredStatusBarStyleExeBlock(); +} + +- (void)clickedPlayOnTabCell:(SJVideoListTableViewCell *)cell playerParentView:(UIView *)playerParentView { + self.playedIndexPath = [self.tableView indexPathForCell:cell]; + SJVideoPlayerURLAsset *asset = + // [[SJVideoPlayerURLAsset alloc] initWithAssetURL:[[NSBundle mainBundle] URLForResource:@"sample" withExtension:@"mp4"] + [[SJVideoPlayerURLAsset alloc] initWithAssetURL:[NSURL URLWithString:@"http://video.cdn.lanwuzhe.com/14945858406905f0c"] + scrollView:self.tableView + indexPath:[self.tableView indexPathForCell:cell] + superviewTag:playerParentView.tag]; + asset.title = @"DIY心情转盘 #手工##手工制作##卖包子喽##1块1个##卖完就撤#"; + asset.alwaysShowTitle = YES; + + [self.videoPlayerHelper playWithAsset:asset playerParentView:playerParentView]; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { + SJVideoPlayerURLAsset *asset = nil; + if ( [self.playedIndexPath isEqual:indexPath] ) { + asset = self.videoPlayerHelper.asset; + } + DemoPlayerViewController *vc = [[DemoPlayerViewController alloc] initWithVideo:self.videos[indexPath.row] asset:asset]; + [self.navigationController pushViewController:vc animated:YES]; +} + +#pragma mark - + +- (void)_videoListSetupViews { + self.view.backgroundColor = [UIColor whiteColor]; + [self.view addSubview:self.tableView]; + [_tableView mas_makeConstraints:^(MASConstraintMaker *make) { + make.edges.offset(0); + }]; +} + +- (UIActivityIndicatorView *)indicator { + if ( _indicator ) return _indicator; + _indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; + _indicator.csj_size = CGSizeMake(80, 80); + _indicator.center = self.view.center; + _indicator.backgroundColor = [UIColor colorWithWhite:0.000 alpha:0.670]; + _indicator.clipsToBounds = YES; + _indicator.layer.cornerRadius = 6; + [self.view addSubview:_indicator]; + return _indicator; +} + +- (UITableView *)tableView { + if ( _tableView ) return _tableView; + _tableView = [SJUITableViewFactory tableViewWithStyle:UITableViewStylePlain backgroundColor:[UIColor whiteColor] separatorStyle:UITableViewCellSeparatorStyleNone showsVerticalScrollIndicator:YES delegate:self dataSource:self]; + [_tableView registerClass:NSClassFromString(SJVideoListTableViewCellID) forCellReuseIdentifier:SJVideoListTableViewCellID]; + return _tableView; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return _videos.count; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + return [SJVideoListTableViewCell heightWithContentHeight:_videos[indexPath.row].videoContentLayout.textBoundingSize.height]; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + SJVideoListTableViewCell * cell = (SJVideoListTableViewCell *)[tableView dequeueReusableCellWithIdentifier:SJVideoListTableViewCellID forIndexPath:indexPath]; + cell.model = _videos[indexPath.row]; + cell.delegate = self; + return cell; +} + +#pragma mark - other +- (void)attributedString:(NSAttributedString *)attrStr tappedStr:(NSAttributedString *)tappedStr { + UIViewController *vc = [[self class] new]; + vc.title = tappedStr.string; + [self.navigationController pushViewController:vc animated:YES]; +} + +- (void)tappedOtherPlacesOfAttributedString:(NSAttributedString *)attrStr { + SJVideoModel *model = attrStr.object; + SJVideoPlayerURLAsset *asset = nil; + if ( [self.videoPlayerHelper.currentPlayURL.absoluteString isEqualToString:model.playURLStr] ) { + asset = self.videoPlayerHelper.asset; + } + DemoPlayerViewController *vc = [[DemoPlayerViewController alloc] initWithVideo:model asset:asset]; + [self.navigationController pushViewController:vc animated:YES]; +} +@end + diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableViewHeader/TableViewHeaderDemoViewController.m b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableViewHeader/TableViewHeaderDemoViewController.m index 60f770894..4656b82c6 100644 --- a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableViewHeader/TableViewHeaderDemoViewController.m +++ b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableViewHeader/TableViewHeaderDemoViewController.m @@ -15,6 +15,7 @@ #import "SJVideoPlayerHelper.h" #import #import "TableHeaderView.h" +#import "DemoPlayerViewController.h" #import "YYTapActionLabel.h" static NSString *const SJVideoListTableViewCellID = @"SJVideoListTableViewCell"; @@ -187,4 +188,13 @@ - (void)attributedString:(NSAttributedString *)attrStr tappedStr:(NSAttributedSt [self.navigationController pushViewController:vc animated:YES]; } +- (void)tappedOtherPlacesOfAttributedString:(NSAttributedString *)attrStr { + SJVideoModel *model = attrStr.object; + SJVideoPlayerURLAsset *asset = nil; + if ( [self.videoPlayerHelper.currentPlayURL.absoluteString isEqualToString:model.playURLStr] ) { + asset = self.videoPlayerHelper.asset; + } + DemoPlayerViewController *vc = [[DemoPlayerViewController alloc] initWithVideo:model asset:asset]; + [self.navigationController pushViewController:vc animated:YES]; +} @end diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Controller/SJVideoListViewController.m b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Controller/SJVideoListViewController.m index f20418479..b63166195 100755 --- a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Controller/SJVideoListViewController.m +++ b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Controller/SJVideoListViewController.m @@ -175,4 +175,13 @@ - (void)attributedString:(NSAttributedString *)attrStr tappedStr:(NSAttributedSt [self.navigationController pushViewController:vc animated:YES]; } +- (void)tappedOtherPlacesOfAttributedString:(NSAttributedString *)attrStr { + SJVideoModel *model = attrStr.object; + SJVideoPlayerURLAsset *asset = nil; + if ( [self.videoPlayerHelper.currentPlayURL.absoluteString isEqualToString:model.playURLStr] ) { + asset = self.videoPlayerHelper.asset; + } + DemoPlayerViewController *vc = [[DemoPlayerViewController alloc] initWithVideo:model asset:asset]; + [self.navigationController pushViewController:vc animated:YES]; +} @end diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoModel.h b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoModel.h index 4517a8f9c..1d86703d7 100755 --- a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoModel.h +++ b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoModel.h @@ -46,6 +46,6 @@ @property (nonatomic, strong, readonly) NSString *nickname; @property (nonatomic, strong, readonly) NSString *avatar; -- (instancetype)initWithNickname:(NSString *)nickName avatar:(NSString *)avatar; +- (instancetype)initWithNickname:(NSString *)nickname avatar:(NSString *)avatar; @end diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoModel.m b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoModel.m index 0f6f238c5..cf24b658d 100755 --- a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoModel.m +++ b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoModel.m @@ -46,16 +46,17 @@ @implementation SJVideoModel // make video title layout [SJVideoListTableViewCell sync_makeVideoContent:^(CGFloat contentMaxWidth, UIFont *font, UIColor *textColor) { - NSString *actionStrRexp = @"([@][^\\s]+\\s)|([#][^#]+#)|((http)[^\\s]+\\s)"; // `string regular` + NSString *rexp = @"([@][^\\s]+\\s)|([#][^#]+#)|((http)[^\\s]+\\s)"; // `string regular` NSMutableAttributedString *attrStr = sj_makeAttributesString(^(SJAttributeWorker * _Nonnull make) { make.font(font).textColor(textColor); make.insert(model.title, 0); - make.regexp(actionStrRexp, ^(SJAttributesRangeOperator * _Nonnull matched) { + make.regexp(rexp, ^(SJAttributesRangeOperator * _Nonnull matched) { matched.textColor([UIColor purpleColor]); }); }); - attrStr.addTapAction(actionStrRexp); + attrStr.addTapAction(rexp); attrStr.tappedDelegate = actionDelegate; + attrStr.object = model; model.videoContentLayout = sj_layout(contentMaxWidth, attrStr); }]; diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoPlayerHelper.h b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoPlayerHelper.h index d44fe7a12..7a1ae18d5 100644 --- a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoPlayerHelper.h +++ b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoPlayerHelper.h @@ -9,11 +9,18 @@ #import NS_ASSUME_NONNULL_BEGIN +typedef NS_ENUM(NSUInteger, SJVideoPlayerType) { + SJVideoPlayerType_Default, + SJVideoPlayerType_Lightweight, +}; + @class SJVideoPlayerURLAsset; @protocol SJVideoPlayerHelperUseProtocol; @interface SJVideoPlayerHelper : NSObject +- (instancetype)initWithViewController:(__weak UIViewController *)viewController playerType:(SJVideoPlayerType)playerType; + /// return instance - (instancetype)initWithViewController:(__weak UIViewController *)viewController; @@ -27,6 +34,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong, readonly, nullable) SJVideoPlayerURLAsset *asset; @property (nonatomic, readonly) NSTimeInterval currentTime; @property (nonatomic, readonly) NSTimeInterval totalTime; +@property (nonatomic, strong, readonly) NSURL *currentPlayURL; @property (nonatomic, copy, readonly) void(^vc_viewDidAppearExeBlock)(void); diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoPlayerHelper.m b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoPlayerHelper.m index 0efcd4739..aa1a128aa 100644 --- a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoPlayerHelper.m +++ b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/Model/SJVideoPlayerHelper.m @@ -29,6 +29,8 @@ @interface SJVideoPlayerHelper () *)viewController { + return [self initWithViewController:viewController playerType:0]; +} + +- (instancetype)initWithViewController:(__weak UIViewController *)viewController playerType:(SJVideoPlayerType)playerType { self = [super init]; if ( !self ) return nil; + self.playerType = playerType; self.viewController = viewController; return self; } @@ -70,7 +77,16 @@ - (void)playWithAsset:(SJVideoPlayerURLAsset *)asset playerParentView:(nonnull U [_videoPlayer stopAndFadeOut]; // create new player - _videoPlayer = [SJVideoPlayer player]; + switch ( _playerType ) { + case SJVideoPlayerType_Default: { + _videoPlayer = [SJVideoPlayer player]; + } + break; + case SJVideoPlayerType_Lightweight: { + _videoPlayer = [SJVideoPlayer lightweightPlayer]; + } + break; + } [playerParentView addSubview:_videoPlayer.view]; [_videoPlayer.view mas_makeConstraints:^(MASConstraintMaker *make) { @@ -310,6 +326,10 @@ - (NSTimeInterval)totalTime { return self.videoPlayer.totalTime; } +- (NSURL *)currentPlayURL { + return self.videoPlayer.assetURL; +} + - (void (^)(void))vc_viewDidAppearExeBlock { __weak typeof(self) _self = self; return ^ () { diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/View/YYTapActionLabel.h b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/View/YYTapActionLabel.h index cf9e4cc96..ac1acfdf7 100644 --- a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/View/YYTapActionLabel.h +++ b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/View/YYTapActionLabel.h @@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @interface NSAttributedString (SJAddDelegate) @property (nonatomic, weak, readwrite, nullable) id tappedDelegate; +@property (nonatomic, strong, nullable) id object; @end @@ -46,13 +47,16 @@ NS_ASSUME_NONNULL_BEGIN */ @property (nonatomic, copy, readonly) void(^addTapAction)(NSString *regStr); + @end #pragma mark - @protocol NSAttributedStringTappedDelegate -@optional - (void)attributedString:(NSAttributedString *)attrStr tappedStr:(NSAttributedString *)tappedStr; +@optional +- (void)tappedOtherPlacesOfAttributedString:(NSAttributedString *)attrStr; + @end NS_ASSUME_NONNULL_END diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/View/YYTapActionLabel.m b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/View/YYTapActionLabel.m index 88d2a84ec..ba6566f19 100644 --- a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/View/YYTapActionLabel.m +++ b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_Demo/View/YYTapActionLabel.m @@ -47,6 +47,9 @@ - (void)setTextLayout:(YYTextLayout *)textLayout { [attributedText.tappedDelegate attributedString:attributedText tappedStr:[attributedText attributedSubstringFromRange:range]]; } } + else if ( [attributedText.tappedDelegate respondsToSelector:@selector(tappedOtherPlacesOfAttributedString:)] ) { + [attributedText.tappedDelegate tappedOtherPlacesOfAttributedString:attributedText]; + } };; } [super setTextLayout:textLayout]; @@ -119,5 +122,13 @@ - (void)setTappedDelegate:(id)tappedDelegate { return objc_getAssociatedObject(self, _cmd); } +- (void)setObject:(id)object { + objc_setAssociatedObject(self, @selector(object), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (id)object { + return objc_getAssociatedObject(self, _cmd); +} + @end diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_TableHeaderIsCollectionView/TableViewHeaderIsCollectionViewDemoViewController.m b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_TableHeaderIsCollectionView/TableViewHeaderIsCollectionViewDemoViewController.m index ceecbe9dc..898431bac 100644 --- a/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_TableHeaderIsCollectionView/TableViewHeaderIsCollectionViewDemoViewController.m +++ b/SJVideoPlayerProject/SJVideoPlayerProject/Demo/TableView_TableHeaderIsCollectionView/TableViewHeaderIsCollectionViewDemoViewController.m @@ -15,6 +15,7 @@ #import "SJVideoPlayerHelper.h" #import #import "TableHeaderCollectionView.h" +#import "DemoPlayerViewController.h" #import "YYTapActionLabel.h" static NSString *const SJVideoListTableViewCellID = @"SJVideoListTableViewCell"; @@ -189,5 +190,14 @@ - (void)attributedString:(NSAttributedString *)attrStr tappedStr:(NSAttributedSt [self.navigationController pushViewController:vc animated:YES]; } +- (void)tappedOtherPlacesOfAttributedString:(NSAttributedString *)attrStr { + SJVideoModel *model = attrStr.object; + SJVideoPlayerURLAsset *asset = nil; + if ( [self.videoPlayerHelper.currentPlayURL.absoluteString isEqualToString:model.playURLStr] ) { + asset = self.videoPlayerHelper.asset; + } + DemoPlayerViewController *vc = [[DemoPlayerViewController alloc] initWithVideo:model asset:asset]; + [self.navigationController pushViewController:vc animated:YES]; +} @end diff --git a/SJVideoPlayerProject/SJVideoPlayerProject/ViewController.m b/SJVideoPlayerProject/SJVideoPlayerProject/ViewController.m index 81231a3f3..e03f6b99f 100755 --- a/SJVideoPlayerProject/SJVideoPlayerProject/ViewController.m +++ b/SJVideoPlayerProject/SJVideoPlayerProject/ViewController.m @@ -19,6 +19,7 @@ #import "TableViewHeaderIsCollectionViewDemoViewController.h" #import "AboutKeyboardViewController.h" #import "DowloadViewController.h" +#import "LightweightViewController.h" @interface ViewController () @@ -77,6 +78,10 @@ - (IBAction)download:(id)sender { [self.navigationController pushViewController:[[DowloadViewController alloc] init] animated:YES]; } +- (IBAction)lightweight:(id)sender { + [self.navigationController pushViewController:[[LightweightViewController alloc] init] animated:YES]; +} + - (IBAction)test:(id)sender { }