- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
// 保存当前播放状态和进度
NSIndexPath * indexPath = [self metalienKK_getCurrentIndexPath];
MetalienKKDynamicModel * currentModel = self.dataSource[indexPath.row];
CGFloat playTime = currentModel.currentPlaybackTime;
BOOL wasPlaying = currentModel.isPlaying;
BOOL willBeFullScreen = (size.width > size.height);
currentModel.isFullScreen = willBeFullScreen;
// 更新控件可见性
self.metalienKK_statusImageView.hidden = willBeFullScreen;
self.backButton.hidden = willBeFullScreen;
self.searchButton.hidden = willBeFullScreen;
self.shareButton.hidden = willBeFullScreen;
self.portraitButton.hidden = !willBeFullScreen;
// 暂停当前播放但不重置
MetalienKKShortVideoItemCollectionViewCell * currentCell = [self.collectionView cellForItemAtIndexPath:indexPath];
[currentCell.metalienKK_playerView metalienKK_pauseShortVideoWithoutReset];
// 更新约束
[self metalienKK_updateContainerFrameForSize:size isFullScreen:willBeFullScreen atIndexPath:indexPath];
// 更新布局而不重载数据
[coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) {
// 立即刷新布局避免闪烁
[UIView performWithoutAnimation:^{
[self.collectionView.collectionViewLayout invalidateLayout];
[self.collectionView layoutIfNeeded];
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredVertically animated:NO];
}];
// 更新旋转状态
[currentCell.metalienKK_playerView metalienKK_shortVideoPlayerViewRotate:willBeFullScreen];
} completion:^(id <UIViewControllerTransitionCoordinatorContext> context) {
self.collectionView.scrollEnabled = !currentModel.isFullScreen;
// 恢复播放状态
if (wasPlaying) {
[currentCell.metalienKK_playerView metalienKK_startPlayShortVideo];
[currentCell.metalienKK_playerView metalienKK_seekToTime:playTime];
} else {
[currentCell.metalienKK_playerView metalienKK_pauseShortVideo];
}
// 执行等待中的动作
if (self.interfaceOrientationBlock) {
self.interfaceOrientationBlock();
self.interfaceOrientationBlock = nil;
}
}];
}
#import "MetalienKKShortVideoPlayerView.h"
#define MetalienKK_kMiniPlayerViewHeight (265.0)
#define MetalienKK_kBottomViewHeight (55.0 + MetalienKK_SafeAreaBottom)
#define MetalienKK_kProgressViewSize CGSizeMake(MetalienKK_ScreenWidth - 15*2.0, 18.0)
#define MetalienKK_kFullScreenDefaultSize CGSizeMake(110, 30)
#define MetalienKK_FullScreenOpenButtonFont MetalienKK_RegularFont(12)
@implementation MetalienKKShortVideoPlayerView
/// 加载子视图
- (void)metalienKK_loadSubviews {
// 新增视图
[self addSubview:self.metalienKK_playerView];
[self addSubview:self.metalienKK_maskView];
[self addSubview:self.metalienKK_bottomView];
[self addSubview:self.metalienKK_durationLabel];
[self addSubview:self.metalienKK_contentView];
[self addSubview:self.metalienKK_userView];
[self addSubview:self.metalienKK_progressView];
[self addSubview:self.metalienKK_popupView];
[self addSubview:self.metalienKK_loadingView];
[self addSubview:self.metalienKK_fullScreenButton];
[self addSubview:self.metalienKK_playImageView];
[self.metalienKK_playerView addSubview:self.metalienKK_videoEngine.playerView];
[self.metalienKK_bottomView addSubview:self.metalienKK_likeButton];
[self.metalienKK_bottomView addSubview:self.metalienKK_bottomLineView_1];
[self.metalienKK_bottomView addSubview:self.metalienKK_bottomLineView_2];
[self.metalienKK_bottomView addSubview:self.metalienKK_commentButton];
[self.metalienKK_bottomView addSubview:self.metalienKK_wowButton];
// 设置约束
[self.metalienKK_bottomView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.bottom.right.equalTo(self);
make.height.mas_offset(MetalienKK_kBottomViewHeight);
}];
[self.metalienKK_likeButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.metalienKK_bottomView);
make.top.equalTo(self.metalienKK_bottomView);
make.width.equalTo(self.metalienKK_bottomView.mas_width).multipliedBy(1/3.0);
make.height.mas_offset(55.0);
}];
[self.metalienKK_bottomLineView_1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.metalienKK_likeButton);
make.right.equalTo(self.metalienKK_likeButton.mas_left);
make.size.mas_offset(CGSizeMake(1, 20));
}];
[self.metalienKK_bottomLineView_2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.metalienKK_likeButton);
make.left.equalTo(self.metalienKK_likeButton.mas_right);
make.size.mas_equalTo(self.metalienKK_bottomLineView_1);
}];
[self.metalienKK_commentButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.equalTo(self.metalienKK_bottomView);
make.right.equalTo(self.metalienKK_bottomLineView_1.mas_left);
make.height.mas_equalTo(self.metalienKK_likeButton);
}];
[self.metalienKK_wowButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.right.equalTo(self.metalienKK_bottomView);
make.left.equalTo(self.metalienKK_bottomLineView_2.mas_right);
make.height.mas_equalTo(self.metalienKK_likeButton);
}];
[self.metalienKK_playerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.equalTo(self);
make.bottom.equalTo(self).offset(-MetalienKK_kBottomViewHeight);
}];
[self.metalienKK_videoEngine.playerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.metalienKK_playerView);
}];
[self.metalienKK_popupView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.mas_bottom); // 初始位置在底部之外
make.left.right.equalTo(self);
make.height.mas_equalTo(MetalienKK_ScreenHeight - MetalienKK_StatusBarHeight - MetalienKK_kMiniPlayerViewHeight);
}];
[self.metalienKK_maskView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.metalienKK_playerView);
}];
[self.metalienKK_playImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.metalienKK_playerView);
make.size.mas_offset(CGSizeMake(40, 40));
}];
[self.metalienKK_progressView mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self);
make.bottom.equalTo(self.metalienKK_bottomView.mas_top);
make.size.mas_offset(MetalienKK_kProgressViewSize);
}];
[self.metalienKK_durationLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.leading.equalTo(self.metalienKK_progressView);
make.bottom.equalTo(self.metalienKK_progressView.mas_top);
}];
[self.metalienKK_contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self);
make.bottom.equalTo(self.metalienKK_progressView.mas_top);
make.height.mas_offset(20.0);
}];
[self.metalienKK_userView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.equalTo(self);
make.bottom.equalTo(self.metalienKK_contentView.mas_top).offset(-12);
make.height.mas_offset(36.0);
}];
[self.metalienKK_fullScreenButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.metalienKK_playerView);
make.size.mas_equalTo(MetalienKK_kFullScreenDefaultSize);
}];
[self.metalienKK_loadingView mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.metalienKK_playerView);
make.left.right.equalTo(self).inset(15.0);
make.height.mas_equalTo(60);
}];
// 按钮布局
[self.metalienKK_commentButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:4.0];
[self.metalienKK_likeButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:4.0];
[self.metalienKK_wowButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:4.0];
// 创建通知
[self metalienKK_setupNotifications];
}
/// 创建通知
- (void)metalienKK_setupNotifications {
// 应用进入后台时暂停
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActiveNotification) name:UIApplicationWillResignActiveNotification object:nil];
// 应用返回前台时恢复
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActiveNotification) name:UIApplicationDidBecomeActiveNotification object:nil];
}
/// 显示&隐藏控件
- (void)metalienKK_showAndHiddenControls {
self.metalienKK_fullScreenButton.hidden = self.responseData.isFullScreen ?:(!self.responseData.isHorizontalResolution);
self.metalienKK_bottomView.hidden = self.responseData.isFullScreen;
self.metalienKK_contentView.hidden = self.responseData.isFullScreen ?:!((self.responseData.isShowTitle || self.responseData.isShowContent));
self.metalienKK_durationLabel.hidden = self.responseData.isFullScreen ? self.responseData.isPlaying:YES;
self.metalienKK_userView.hidden = self.responseData.isFullScreen ? self.responseData.isPlaying:NO;
self.metalienKK_progressView.hidden = self.responseData.isFullScreen ? self.responseData.isPlaying:NO;
}
/// 重置约束
- (void)metalienKK_remarkConstraints {
// 视频播放器
[self.metalienKK_playerView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self);
make.left.right.equalTo(self).inset(self.responseData.isFullScreen ? 76.0:0.0);
make.bottom.equalTo(self).offset(self.responseData.isFullScreen ? 0.0:(-MetalienKK_kBottomViewHeight));
}];
[self.metalienKK_videoEngine.playerView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.metalienKK_playerView);
}];
// 用户信息视图
[self.metalienKK_userView mas_remakeConstraints:^(MASConstraintMaker *make) {
if (self.responseData.isFullScreen) {
make.top.equalTo(self).offset(20);
make.left.right.equalTo(self).inset(94);
} else {
make.left.right.equalTo(self);
if (!self.metalienKK_contentView.hidden) {
make.bottom.equalTo(self.metalienKK_contentView.mas_top).offset(-12);
} else {
make.bottom.equalTo(self.metalienKK_progressView.mas_top);
}
}
make.height.mas_offset(36.0);
}];
// 进度条
[self.metalienKK_progressView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self);
if (self.responseData.isFullScreen) {
make.left.right.equalTo(self).inset(50);
make.bottom.equalTo(self).offset(-39);
make.height.mas_equalTo(MetalienKK_kProgressViewSize.height);
} else {
make.bottom.equalTo(self.metalienKK_bottomView.mas_top);
make.size.mas_offset(MetalienKK_kProgressViewSize);
}
}];
// 内容
if (!self.metalienKK_contentView.hidden)
{
[self.metalienKK_contentView mas_remakeConstraints:^(MASConstraintMaker *make) {
CGFloat contentHeight = [self.metalienKK_contentView metalienKK_getContentViewHeight];
make.left.right.equalTo(self);
make.bottom.equalTo(self.metalienKK_progressView.mas_top);
make.height.mas_offset(contentHeight);
}];
}
// 全屏播放按钮
if (!self.metalienKK_fullScreenButton.hidden)
{
[self.metalienKK_fullScreenButton mas_remakeConstraints:^(MASConstraintMaker *make) {
CGSize tempSize = [self.metalienKK_fullScreenButton.currentTitle metalienKK_calculateMultipleLinesTextSizeWithFont:MetalienKK_FullScreenOpenButtonFont andMaxSize:CGSizeMake(CGFLOAT_MAX, MetalienKK_kFullScreenDefaultSize.height)];
CGFloat tempWidth = 2*12.0 + 20.0 + 8.0 + tempSize.width;
if (tempWidth < MetalienKK_kFullScreenDefaultSize.width) { tempWidth = MetalienKK_kFullScreenDefaultSize.width; }
CGFloat tempVideoHeight = (self.responseData.videoHeight/(self.responseData.videoWidth*1.0)) * MetalienKK_ScreenWidth;
make.centerX.equalTo(self.metalienKK_playerView);
make.centerY.equalTo(self.metalienKK_playerView).offset(tempVideoHeight/2.0 + 12.0 + MetalienKK_kFullScreenDefaultSize.height/2.0);
make.size.mas_equalTo(CGSizeMake(tempWidth, MetalienKK_kFullScreenDefaultSize.height));
}];
}
// 立即刷新
[self layoutIfNeeded];
}
# pragma mark - Public
/// 视图复用
- (void)metalienKK_shortVideoPlayerViewReuse {
// 暂停播放
[self metalienKK_pauseShortVideo];
// 重置播放器
[self.metalienKK_videoEngine resetPlayerVideoProcessor];
}
/// 视图旋转
- (void)metalienKK_shortVideoPlayerViewRotate:(BOOL)isFullScreen {
// 标记
self.responseData.isFullScreen = isFullScreen;
// 显示&隐藏控件
[self metalienKK_showAndHiddenControls];
// 重置约束
[self metalienKK_remarkConstraints];
}
/// 刷新数据
- (void)metalienKK_reloadVideoPlayerViewWithData:(MetalienKKDynamicModel *)responseData {
// 缓存
self.responseData = responseData;
// 显示&隐藏控件
self.metalienKK_loadingView.hidden = responseData.isReadyDisplay;
self.metalienKK_playImageView.hidden = YES;
self.metalienKK_fullScreenButton.hidden = !responseData.isHorizontalResolution;
// 刷新数据
[self.metalienKK_userView metalienKK_refreshShortVideoUser:responseData];
[self.metalienKK_popupView metalienKK_reloadShortVideoViewData:responseData];
// 判断是否显示文本
BOOL isShowContent = (responseData.isShowTitle || responseData.isShowContent);
self.metalienKK_contentView.hidden = !isShowContent;
if (isShowContent) {
[self.metalienKK_contentView metalienKK_refreshShortVideoContent:responseData];
}
// 视频进度
[self.metalienKK_progressView metalienKK_shortVideoSetProgress:responseData.currentPlaybackProgress];
// 设置视频资源
[self metalienKK_setupVideoEngineSource];
// 显示&隐藏控件
[self metalienKK_showAndHiddenControls];
// 重置约束
[self metalienKK_remarkConstraints];
}
/// 设置视频资源
- (void)metalienKK_setupVideoEngineSource {
if (self.responseData.metalienKK_mediaID.length > 0 && self.responseData.metalienKK_mediaToken.length > 0) {
// 设置视频资源(使用 Video ID)
[self metalienKK_setShortVideoSourceWithVideoID:self.responseData.metalienKK_mediaID andToken:self.responseData.metalienKK_mediaToken];
} else if (self.responseData.metalienKK_href.length > 0) {
// 设置视频资源(使用 HTTP URL)
[self metalienKK_setShortVideoSourceWithURL:self.responseData.metalienKK_href];
}
}
/// 预加载方法
- (void)metalienKK_preloadVideo {
// 设置视频资源
[self metalienKK_setupVideoEngineSource];
// 准备播放
[self.metalienKK_videoEngine prepareToPlay];
}
/// 开始播放
- (void)metalienKK_startPlayShortVideo {
// 标识
self.responseData.isPlaying = YES;
// 隐藏播放按钮
self.metalienKK_playImageView.hidden = YES;
// 弱引用
MetalienKK_WeakSelf(self);
// 播放进度
[self.metalienKK_videoEngine addPeriodicTimeObserverForInterval:0.5 queue:dispatch_get_main_queue() usingBlock:^{
// 强引用
MetalienKK_StrongSelf(self);
// 刷新视频播放进度
[self metalienKK_refreshShortVideoPlaybackProgress];
}];
// 指定视频播放开始时间
[self.metalienKK_videoEngine setOptionForKey:VEKKeyPlayerStartTime_CGFloat value:@(self.responseData.currentPlaybackTime)];
// 播放视频
[self.metalienKK_videoEngine play];
}
/// 暂停播放
- (void)metalienKK_pauseShortVideo {
// 显示播放按钮
self.metalienKK_playImageView.hidden = NO;
// 手动标记
self.responseData.isPlaying = NO;
// 暂停播放
[self.metalienKK_videoEngine pause:YES];
// 移除监听
[self.metalienKK_videoEngine removeTimeObserver];
}
/// 重置播放器
- (void)metalienKK_resetPlayer {
// 显示播放按钮
self.metalienKK_playImageView.hidden = NO;
// 手动标记
self.responseData.isPlaying = NO;
// // 视频进度
// [self.metalienKK_progressView metalienKK_shortVideoSetProgress:0];
// 移除监听
[self.metalienKK_videoEngine removeTimeObserver];
// 重置播放器
[self.metalienKK_videoEngine pause:YES];
// [self.metalienKK_videoEngine resetPlayerVideoProcessor];
}
// 无重置的暂停
- (void)metalienKK_pauseShortVideoWithoutReset {
[self.metalienKK_videoEngine pause];
self.responseData.isPlaying = NO;
}
// 跳转到指定时间
- (void)metalienKK_seekToTime:(CGFloat)time {
MetalienKK_WeakSelf(self);
[self.metalienKK_videoEngine setCurrentPlaybackTime:time complete:^(BOOL success) {
if (success) {
[weak_self metalienKK_refreshShortVideoPlaybackProgress];
}
}];
}
# pragma mark - Notification Event
/// App 进入后台
- (void)appWillResignActiveNotification {
if (self.responseData.isPlaying) {
[self metalienKK_pauseShortVideo];
}
}
/// App 即将进入前台
- (void)appDidBecomeActiveNotification {
if (self.responseData.isPlaying) {
[self metalienKK_startPlayShortVideo];
}
}
# pragma mark - Event
/// 设置视频资源(使用 Video ID)
- (void)metalienKK_setShortVideoSourceWithVideoID:(NSString *)videoID andToken:(NSString *)token {
TTVideoEngineVidSource * videoSource = [[TTVideoEngineVidSource alloc] initWithVid:videoID playAuthToken:token resolution:TTVideoEngineResolutionTypeAuto];
[self.metalienKK_videoEngine setVideoEngineVideoSource:videoSource];
}
/// 设置视频资源(使用 HTTP URL)
- (void)metalienKK_setShortVideoSourceWithURL:(NSString *)videoURL {
NSString * cacheKey = [videoURL metalienKK_coverToMD5String];
TTVideoEngineUrlSource * urlSource = [[TTVideoEngineUrlSource alloc] initWithUrl:videoURL cacheKey:cacheKey];
[self.metalienKK_videoEngine setVideoEngineVideoSource:urlSource];
}
/// 刷新视频播放进度
- (void)metalienKK_refreshShortVideoPlaybackProgress {
CGFloat playTime = self.metalienKK_videoEngine.currentPlaybackTime;
CGFloat duration = self.metalienKK_videoEngine.duration;
CGFloat progress = (playTime/duration);
[self.metalienKK_progressView metalienKK_shortVideoSetProgress:progress];
// 视频播放进度
NSString * playTimeString = [NSString metalienKK_secondConvertToFormat:playTime];
NSString * durationString = [NSString metalienKK_secondConvertToFormat:duration];
NSString * content = [NSString stringWithFormat:@"%@ / %@", playTimeString, durationString];
NSRange playTimeRange = [content rangeOfString:playTimeString];
NSMutableAttributedString * attributedString = [[NSMutableAttributedString alloc] initWithString:content];
[attributedString addAttribute:NSForegroundColorAttributeName value:MetalienKK_ColorHexAlpha(@"#A8B0B9", 0.7) range:attributedString.yy_rangeOfAll];
[attributedString addAttribute:NSForegroundColorAttributeName value:UIColor.whiteColor range:playTimeRange];
self.metalienKK_durationLabel.attributedText = attributedString;
// 缓存
self.responseData.currentPlaybackProgress = progress;
self.responseData.currentPlaybackTime = playTime;
}
/// 弹出视图
- (void)metalienKK_showPopupViewAtIndex:(int)index {
// 选中处理
if (index >= 0) {
[self.metalienKK_popupView metalienKK_popupViewDidSelectIndex:index];
}
// 控件显示&隐藏
self.metalienKK_fullScreenButton.hidden = YES;
self.metalienKK_popupView.hidden = NO;
// 标记是否弹出视图
[self metalienKK_markPopupViewIsShow:YES];
// 重置约束
[self.metalienKK_playerView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.equalTo(self);
make.height.mas_equalTo(MetalienKK_kMiniPlayerViewHeight);
}];
[self.metalienKK_popupView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.metalienKK_playerView.mas_bottom);
make.left.right.equalTo(self);
make.height.mas_equalTo(MetalienKK_ScreenHeight - MetalienKK_StatusBarHeight - MetalienKK_kMiniPlayerViewHeight);
}];
// 创建弹簧动画器
UISpringTimingParameters * springParams = [[UISpringTimingParameters alloc] initWithDampingRatio:0.75 initialVelocity:CGVectorMake(0.5, 0.5)];
UIViewPropertyAnimator * animator = [[UIViewPropertyAnimator alloc] initWithDuration:0.4 timingParameters:springParams];
[animator addAnimations:^{
// 强制立即刷新布局
[self layoutIfNeeded];
}];
[animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
[self metalienKK_disableCollectionViewScroll:YES];
}];
[animator startAnimation];
}
/// 关闭视图
- (void)metalienKK_closePopupView {
// 标记是否弹出视图
[self metalienKK_markPopupViewIsShow:NO];
// 重置约束
[self.metalienKK_playerView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.left.right.equalTo(self);
make.bottom.equalTo(self).offset(-MetalienKK_kBottomViewHeight);
}];
[self.metalienKK_popupView mas_remakeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.mas_bottom);
make.left.right.equalTo(self);
make.height.mas_equalTo(MetalienKK_ScreenHeight - MetalienKK_StatusBarHeight - MetalienKK_kMiniPlayerViewHeight);
}];
// 使用相同的动画参数
UISpringTimingParameters * springParams = [[UISpringTimingParameters alloc] initWithDampingRatio:0.8 initialVelocity:CGVectorMake(0, 0)];
UIViewPropertyAnimator * animator = [[UIViewPropertyAnimator alloc] initWithDuration:0.35 timingParameters:springParams];
[animator addAnimations:^{
// 强制立即刷新布局
[self layoutIfNeeded];
}];
[animator addCompletion:^(UIViewAnimatingPosition finalPosition) {
self.metalienKK_fullScreenButton.hidden = !self.responseData.isHorizontalResolution;
self.metalienKK_popupView.hidden = YES;
[self metalienKK_disableCollectionViewScroll:NO];
}];
[animator startAnimation];
}
/// 标记是否弹出视图
- (void)metalienKK_markPopupViewIsShow:(BOOL)isShow {
// 缓存
self.responseData.isShowingPopupView = isShow;
// 弹出&收起视图
if ([self.delegate respondsToSelector:@selector(metalienKK_collectionViewCellDidShowPopupView:)]) {
[self.delegate metalienKK_collectionViewCellDidShowPopupView:isShow];
}
}
/// 禁止滚动
- (void)metalienKK_disableCollectionViewScroll:(BOOL)isDisable {
// 移除手势
[self.metalienKK_maskView removeGestureRecognizer:self.metalienKK_maskViewBlockPanGesture];
// 判断是否禁止
if (isDisable) {
[self.metalienKK_maskView addGestureRecognizer:self.metalienKK_maskViewBlockPanGesture];
}
}
# pragma mark - Gesture
/// 点击视频
- (void)metalienKK_maskViewTapGesture:(UITapGestureRecognizer *)gesture {
// 判断是否正在弹出视图
if (self.responseData.isShowingPopupView) {
[self metalienKK_closePopupView];
} else {
if (self.metalienKK_videoEngine.playbackState == TTVideoEnginePlaybackStatePlaying) {
[self metalienKK_pauseShortVideo];
} else {
[self metalienKK_startPlayShortVideo];
}
}
}
/// 点击内容视图
- (void)metalienKK_contentViewTapGesture:(UITapGestureRecognizer *)gesture {
[self metalienKK_showPopupViewAtIndex:0];
}
/// 视频窗口滑动手势
- (void)metalienKK_maskViewPanGesture:(UIPanGestureRecognizer *)gesture {
// Nothing ...
}
/// 预览视图滑动手势
- (void)metalienKK_popupViewPanGesture:(UIPanGestureRecognizer *)gesture {
static CGPoint originalCenter;
static CGRect originalFrame;
static CGFloat initialTranslationY;
CGPoint translation = [gesture translationInView:self];
CGPoint velocity = [gesture velocityInView:self];
switch (gesture.state) {
case UIGestureRecognizerStateBegan:
// 记录初始位置
originalCenter = self.metalienKK_popupView.center;
originalFrame = self.metalienKK_popupView.frame;
initialTranslationY = translation.y;
break;
case UIGestureRecognizerStateChanged: {
// 计算新的Y位置(限制在屏幕范围内)
CGFloat newY = originalFrame.origin.y + translation.y;
CGFloat minY = MetalienKK_kMiniPlayerViewHeight;
CGFloat maxY = MetalienKK_ScreenHeight;
// 限制拖拽范围(不能超过屏幕顶部/底部)
newY = MIN(MAX(newY, minY), maxY);
// 应用新位置
CGRect newFrame = originalFrame;
newFrame.origin.y = newY;
self.metalienKK_popupView.frame = newFrame;
// 计算背景视图的高度变化(跟随拖拽)
CGFloat backgroundHeight = MetalienKK_kMiniPlayerViewHeight + (newY - minY);
[self.metalienKK_playerView mas_updateConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(backgroundHeight);
}];
[self layoutIfNeeded];
break;
}
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled: {
CGFloat currentY = self.metalienKK_popupView.frame.origin.y;
CGFloat threshold = MetalienKK_ScreenHeight * 0.5; // 阈值设为屏幕高度的50%
BOOL shouldClose = NO;
// 根据速度或位置决定操作
if (velocity.y > 800) {
// 快速下滑则关闭
shouldClose = YES;
} else if (velocity.y < -800) {
// 快速上滑则展开
shouldClose = NO;
} else {
// 根据位置决定
shouldClose = (currentY > threshold);
}
if (shouldClose) {
[self metalienKK_closePopupView];
} else {
[self metalienKK_showPopupViewAtIndex:-999];
}
break;
}
default:
break;
}
}
#pragma mark - Action
/// 全屏播放
- (void)metalienKK_fullScreenButtonAction:(UIButton *)sender {
// 确保使用主线程执行旋转
dispatch_async(dispatch_get_main_queue(), ^{
if ([self.delegate respondsToSelector:@selector(metalienKK_fullScreenOpenButtonDidClick:)]) {
[self.delegate metalienKK_fullScreenOpenButtonDidClick:sender];
}
});
}
/// 评论
- (void)metalienKK_commentButtonAction:(UIButton *)sender {
[self metalienKK_showPopupViewAtIndex:1];
}
/// 赞 & 取消赞
- (void)metalienKK_likeButtonAction:(UIButton *)sender {
}
/// 棒 & 取消棒
- (void)metalienKK_wowButtonAction:(UIButton *)sender {
}
# pragma mark - TTVideoEngineDelegate
/// 播放停止回调
- (void)videoEngineUserStopped:(TTVideoEngine *)videoEngine {
MetalienKK_Log(@"videoEngineUserStopped:");
}
/// 播放结束回调
- (void)videoEngineDidFinish:(TTVideoEngine *)videoEngine error:(nullable NSError *)error {
MetalienKK_Log(@"videoEngineDidFinish:error:");
}
/// 异常播放结束回调
- (void)videoEngineDidFinish:(TTVideoEngine *)videoEngine videoStatusException:(NSInteger)status {
MetalienKK_Log(@"videoEngineDidFinish:videoStatusException:");
}
/// 播放器实例销毁回调
- (void)videoEngineCloseAysncFinish:(TTVideoEngine *)videoEngine {
MetalienKK_Log(@"videoEngineCloseAysncFinish:");
}
/// 播放状态改变回调
- (void)videoEngine:(TTVideoEngine *)videoEngine playbackStateDidChanged:(TTVideoEnginePlaybackState)playbackState {
MetalienKK_Log(@"videoEngine:playbackStateDidChanged:");
self.responseData.isPlaying = (playbackState == TTVideoEnginePlaybackStatePlaying);
self.metalienKK_progressView.isPlaying = self.responseData.isPlaying;
// 显示&隐藏控件
[self metalienKK_showAndHiddenControls];
}
/// 加载状态改变回调
- (void)videoEngine:(TTVideoEngine *)videoEngine loadStateDidChanged:(TTVideoEngineLoadState)loadState {
MetalienKK_Log(@"videoEngine:loadStateDidChanged:");
if (loadState == TTVideoEngineLoadStatePlayable) {
self.responseData.isLoading = NO;
[self.metalienKK_progressView metalienKK_shortVideoStopLoadingAnimation];
} else {
self.responseData.isLoading = YES;
[self.metalienKK_progressView metalienKK_shortVideoStartLoadingAnimation];
}
}
/// 播放器各模块准备完成、可以播放回调
- (void)videoEnginePrepared:(TTVideoEngine *)videoEngine {
MetalienKK_Log(@"videoEnginePrepared:");
self.metalienKK_progressView.duration = videoEngine.duration;
}
/// 视频加载完成、开始播放回调
- (void)videoEngineReadyToPlay:(TTVideoEngine *)videoEngine {
MetalienKK_Log(@"videoEngineReadyToPlay:");
}
/// 显示视频首帧回调
- (void)videoEngineReadyToDisPlay:(TTVideoEngine *)videoEngine {
MetalienKK_Log(@"videoEngineReadyToDisPlay:(width:%ld, height:%ld)", self.responseData.videoWidth, self.responseData.videoHeight);
self.responseData.isReadyDisplay = YES;
self.metalienKK_loadingView.hidden = YES;
}
# pragma mark - TTVideoEngineResolutionDelegate
/// 视频分辨率发生变化回调
- (void)videoSizeDidChange:(TTVideoEngine *)videoEngine videoWidth:(NSInteger)videoWidth videoHeight:(NSInteger)videoHeight {
MetalienKK_Log(@"videoSizeDidChange:videoWidth:%ld videoHeight:%ld", (long)videoWidth, (long)videoHeight);
// 缓存信息
self.responseData.videoWidth = videoWidth;
self.responseData.videoHeight = videoHeight;
// 按钮显示状态
self.responseData.isHorizontalResolution = (self.responseData.videoWidth > self.responseData.videoHeight);
self.metalienKK_fullScreenButton.hidden = !self.responseData.isHorizontalResolution;
// 重置约束
[self metalienKK_remarkConstraints];
}
# pragma mark - Override
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (self.responseData.isShowingPopupView) {
CGPoint commentPoint = [self.metalienKK_popupView convertPoint:point fromView:self];
if ([self.metalienKK_popupView pointInside:commentPoint withEvent:event]) {
return [self.metalienKK_popupView hitTest:commentPoint withEvent:event];
}
CGPoint maskPoint = [self.metalienKK_maskView convertPoint:point fromView:self];
if ([self.metalienKK_maskView pointInside:maskPoint withEvent:event]) {
return self.metalienKK_maskView;
}
return self;
}
return [super hitTest:point withEvent:event];
}
//# pragma mark - Helper
//
///// 判断视图是否存在
//- (BOOL)metalienKK_isVideoEnginePlayerViewExist {
// return [self.metalienKK_videoEngine.playerView isDescendantOfView:self.metalienKK_playerView];
//}
# pragma mark - Getter
- (TTVideoEngine *)metalienKK_videoEngine {
if (!_metalienKK_videoEngine) {
_metalienKK_videoEngine = [[TTVideoEngine alloc] initWithOwnPlayer:YES];
_metalienKK_videoEngine.delegate = self;
_metalienKK_videoEngine.resolutionDelegate = self;
_metalienKK_videoEngine.looping = YES;
[_metalienKK_videoEngine setOptionForKey:VEKKeyViewScaleMode_ENUM value:@(TTVideoEngineScalingModeAspectFit)];
[_metalienKK_videoEngine setOptionForKey:VEKKeyAudioChannelEffect_ENUM value:@(TTVideoEngineAudioChannelNormal)];
// 播放 DASH 视频
[_metalienKK_videoEngine setOptionForKey:VEKKeyPlayerBashEnabled_BOOL value:@(YES)];
[_metalienKK_videoEngine setOptionForKey:VEKKeyPlayerDashEnabled_BOOL value:@(YES)];
}
return _metalienKK_videoEngine;
}
- (MetalienKKShortVideoProgressView *)metalienKK_progressView {
if (!_metalienKK_progressView) {
// 弱引用
MetalienKK_WeakSelf(self);
// 初始化
_metalienKK_progressView = [[MetalienKKShortVideoProgressView alloc] initWithFrame:CGRectMake(0, 0, MetalienKK_kProgressViewSize.width, MetalienKK_kProgressViewSize.height)];
[_metalienKK_progressView setOnSeek:^(NSInteger time) {
// 强引用
MetalienKK_StrongSelf(self);
// 跳转到指定的时间位置
[self.metalienKK_videoEngine setCurrentPlaybackTime:time complete:^(BOOL success) {
// Nothing ...
}];
}];
[_metalienKK_progressView metalienKK_shortVideoStartLoadingAnimation];
}
return _metalienKK_progressView;
}
- (MetalienKKShortVideoContentPreviewView *)metalienKK_contentView {
if (!_metalienKK_contentView) {
_metalienKK_contentView = [[MetalienKKShortVideoContentPreviewView alloc] init];
_metalienKK_contentView.userInteractionEnabled = YES;
// 添加手势
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_contentViewTapGesture:)];
[_metalienKK_contentView addGestureRecognizer:tap];
}
return _metalienKK_contentView;
}
- (MetalienKKShortVideoUserView *)metalienKK_userView {
if (!_metalienKK_userView) {
_metalienKK_userView = [[MetalienKKShortVideoUserView alloc] init];
}
return _metalienKK_userView;
}
- (UIView *)metalienKK_playerView {
if (!_metalienKK_playerView) {
_metalienKK_playerView = [[UIView alloc] init];
_metalienKK_playerView.userInteractionEnabled = YES;
}
return _metalienKK_playerView;
}
- (UIView *)metalienKK_bottomView {
if (!_metalienKK_bottomView) {
_metalienKK_bottomView = [[UIView alloc] init];
_metalienKK_bottomView.backgroundColor = MetalienKK_ColorHex(@"#11111D");
}
return _metalienKK_bottomView;
}
- (UIButton *)metalienKK_commentButton {
if (!_metalienKK_commentButton) {
_metalienKK_commentButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_metalienKK_commentButton.titleLabel setFont:MetalienKK_BoldFont(14)];
[_metalienKK_commentButton setTitle:MetalienKK_LocalizedString(@"评论") forState:UIControlStateNormal];
[_metalienKK_commentButton setTitleColor:MetalienKK_ColorHex(@"#E6EBF4") forState:UIControlStateNormal];
[_metalienKK_commentButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_comment"] forState:UIControlStateNormal];
[_metalienKK_commentButton addTarget:self action:@selector(metalienKK_commentButtonAction:) forControlEvents:UIControlEventTouchUpInside];
}
return _metalienKK_commentButton;
}
- (UIButton *)metalienKK_likeButton {
if (!_metalienKK_likeButton) {
_metalienKK_likeButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_metalienKK_likeButton.titleLabel setFont:MetalienKK_BoldFont(14)];
[_metalienKK_likeButton setTitle:MetalienKK_LocalizedString(@"赞") forState:UIControlStateNormal];
[_metalienKK_likeButton setTitleColor:MetalienKK_ColorHex(@"#E6EBF4") forState:UIControlStateNormal];
[_metalienKK_likeButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_like"] forState:UIControlStateNormal];
[_metalienKK_likeButton addTarget:self action:@selector(metalienKK_likeButtonAction:) forControlEvents:UIControlEventTouchUpInside];
}
return _metalienKK_likeButton;
}
- (UIButton *)metalienKK_wowButton {
if (!_metalienKK_wowButton) {
_metalienKK_wowButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_metalienKK_wowButton.titleLabel setFont:MetalienKK_BoldFont(14)];
[_metalienKK_wowButton setTitle:MetalienKK_LocalizedString(@"棒") forState:UIControlStateNormal];
[_metalienKK_wowButton setTitleColor:MetalienKK_ColorHex(@"#E6EBF4") forState:UIControlStateNormal];
[_metalienKK_wowButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_WOW"] forState:UIControlStateNormal];
[_metalienKK_wowButton addTarget:self action:@selector(metalienKK_wowButtonAction:) forControlEvents:UIControlEventTouchUpInside];
}
return _metalienKK_wowButton;
}
- (UIView *)metalienKK_bottomLineView_1 {
if (!_metalienKK_bottomLineView_1) {
_metalienKK_bottomLineView_1 = [[UIView alloc] init];
_metalienKK_bottomLineView_1.backgroundColor = MetalienKK_ColorHexAlpha(@"#848C96", 0.1);
}
return _metalienKK_bottomLineView_1;
}
- (UIView *)metalienKK_bottomLineView_2 {
if (!_metalienKK_bottomLineView_2) {
_metalienKK_bottomLineView_2 = [[UIView alloc] init];
_metalienKK_bottomLineView_2.backgroundColor = MetalienKK_ColorHexAlpha(@"#848C96", 0.1);
}
return _metalienKK_bottomLineView_2;
}
- (UIImageView *)metalienKK_playImageView {
if (!_metalienKK_playImageView) {
_metalienKK_playImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"metalienKKImage_shortVideoPlay"]];
_metalienKK_playImageView.hidden = YES;
}
return _metalienKK_playImageView;
}
- (UIView *)metalienKK_maskView {
if (!_metalienKK_maskView) {
_metalienKK_maskView = [[UIView alloc] init];
_metalienKK_maskView.backgroundColor = UIColor.clearColor;
_metalienKK_maskView.userInteractionEnabled = YES;
// 添加手势
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_maskViewTapGesture:)];
[_metalienKK_maskView addGestureRecognizer:tap];
}
return _metalienKK_maskView;
}
- (UIPanGestureRecognizer *)metalienKK_maskViewBlockPanGesture {
if (!_metalienKK_maskViewBlockPanGesture) {
_metalienKK_maskViewBlockPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_maskViewPanGesture:)];
}
return _metalienKK_maskViewBlockPanGesture;
}
- (UIPanGestureRecognizer *)metalienKK_popupViewPanGesture {
if (!_metalienKK_popupViewPanGesture) {
_metalienKK_popupViewPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(metalienKK_popupViewPanGesture:)];
}
return _metalienKK_popupViewPanGesture;
}
- (MetalienKKShortVideoPopupView *)metalienKK_popupView {
if (!_metalienKK_popupView) {
// 初始化视图
_metalienKK_popupView = [[MetalienKKShortVideoPopupView alloc] init];
_metalienKK_popupView.backgroundColor = [UIColor whiteColor];
_metalienKK_popupView.clipsToBounds = YES;
_metalienKK_popupView.layer.cornerRadius = 12.0;
_metalienKK_popupView.hidden = YES;
_metalienKK_popupView.parentViewPanGestureRecognizer = self.metalienKK_popupViewPanGesture;
// 添加拖拽手势
[_metalienKK_popupView addGestureRecognizer:self.metalienKK_popupViewPanGesture];
// 添加按钮事件
[_metalienKK_popupView.metalienKK_commentView.metalienKK_closeButton addTarget:self action:@selector(metalienKK_closePopupView) forControlEvents:UIControlEventTouchUpInside];
}
return _metalienKK_popupView;
}
- (UIButton *)metalienKK_fullScreenButton {
if (!_metalienKK_fullScreenButton) {
_metalienKK_fullScreenButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_metalienKK_fullScreenButton setFrame:CGRectMake(0, 0, MetalienKK_kFullScreenDefaultSize.width, MetalienKK_kFullScreenDefaultSize.height)];
[_metalienKK_fullScreenButton.titleLabel setFont:MetalienKK_FullScreenOpenButtonFont];
[_metalienKK_fullScreenButton setTitle:MetalienKK_LocalizedString(@"全屏播放") forState:UIControlStateNormal];
[_metalienKK_fullScreenButton setTitleColor:UIColor.whiteColor forState:UIControlStateNormal];
[_metalienKK_fullScreenButton setImage:[UIImage imageNamed:@"metalienKKImage_shortVideo_fullScreen_open"] forState:UIControlStateNormal];
[_metalienKK_fullScreenButton setClipsToBounds:YES];
[_metalienKK_fullScreenButton.layer setCornerRadius:MetalienKK_kFullScreenDefaultSize.height/2.0];
[_metalienKK_fullScreenButton.layer setBorderColor:MetalienKK_ColorHexAlpha(@"#FFFFFF", 0.15).CGColor];
[_metalienKK_fullScreenButton.layer setBorderWidth:1.0];
[_metalienKK_fullScreenButton addTarget:self action:@selector(metalienKK_fullScreenButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[_metalienKK_fullScreenButton metalienKK_layoutWithStyle:MetalienKKButtonEdgeInsetsStyleImageLeft andSpace:8.0];
[_metalienKK_fullScreenButton setHidden:YES];
}
return _metalienKK_fullScreenButton;
}
- (UILabel *)metalienKK_durationLabel {
if (!_metalienKK_durationLabel) {
_metalienKK_durationLabel = [[UILabel alloc] init];
_metalienKK_durationLabel.font = MetalienKK_RegularFont(14);
_metalienKK_durationLabel.text = @"00:00 / 00:00";
_metalienKK_durationLabel.textColor = MetalienKK_ColorHexAlpha(@"#A8B0B9", 0.7);
_metalienKK_durationLabel.hidden = YES;
}
return _metalienKK_durationLabel;
}
- (UIView *)metalienKK_loadingView {
if (!_metalienKK_loadingView) {
_metalienKK_loadingView = [[UIView alloc] init];
_metalienKK_loadingView.hidden = YES;
// 添加图标
UIImageView * iconImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"metalienKKImage_metalienIconBig"]];
iconImageView.contentMode = UIViewContentModeScaleAspectFit;
[_metalienKK_loadingView addSubview:iconImageView];
[iconImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.centerX.equalTo(_metalienKK_loadingView);
make.size.mas_equalTo(CGSizeMake(40, 40));
}];
// 添加说明
UILabel * tipLabel = [[UILabel alloc] init];
tipLabel.font = MetalienKK_RegularFont(12);
tipLabel.text = MetalienKK_LocalizedString(@"加载中...");
tipLabel.textColor = MetalienKK_ColorHexAlpha(@"#848C96", 0.6);
[_metalienKK_loadingView addSubview:tipLabel];
[tipLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(_metalienKK_loadingView);
make.bottom.equalTo(_metalienKK_loadingView);
}];
}
return _metalienKK_loadingView;
}
# pragma mark - Dealloc
- (void)dealloc {
// 移除通知
[[NSNotificationCenter defaultCenter] removeObserver:self];
// 销毁播放器
[self.metalienKK_videoEngine stop];
[self.metalienKK_videoEngine removeTimeObserver];
[self.metalienKK_videoEngine.playerView removeFromSuperview];
[self.metalienKK_videoEngine closeAysnc];
self.metalienKK_videoEngine = nil;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
旋转视图时,为什么播放器的视频会黑一下,再显示出来的?
最新发布