UIPanGestureRecognizer类中translationInView方法和velocityInView方法有什么区别

本文详细介绍了如何利用UIPanGestureRecognizer实现图片在界面上的自由拖动,并通过handlePan函数处理拖动事件,解析了translationInView:和velocityInView:方法的API解释,提供了代码示例和理解说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UIPanGestureRecognizer主要用于拖动,比如桌面上有一张图片uiimageview,你想让它由原始位置拖到任何一个位置,就是图片跟着你的手指走动,那么就需要用到该类了。

以下代码表示给一个图片视图指定一个UIPanGestureRecognizer手势当该图片捕获到用户的拖动手势时会调用回调函数handlePan

 

C代码   收藏代码
  1. UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];  
  2.     [self.imgView setUserInteractionEnabled:YES];  
  3.     [self.imgView addGestureRecognizer:pan];  
  4.     [pan release];  

 handlePan函数代码如下:

 

C代码   收藏代码
  1. - (void) handlePan: (UIPanGestureRecognizer *)rec{  
  2.     NSLog(@"xxoo---xxoo---xxoo");        
  3.     CGPoint point = [rec translationInView:self.view];  
  4.     NSLog(@"%f,%f",point.x,point.y);  
  5.     rec.view.center = CGPointMake(rec.view.center.x + point.x, rec.view.center.y + point.y);  
  6.     [rec setTranslation:CGPointMake(0, 0) inView:self.view];  
  7. }  

 以下为本人自己的理解,有不到之处请看官务必指教12


- (CGPoint)translationInView:(UIView *)view方法的API解释如下:


The translation of the pan gesture in the coordinate system of the specified view.


Return Value

A point identifying the new location of a view in the coordinate system of its designated superview.

字面理解是:

在指定的视图坐标系统中转换(拖动?) pan gesture

返回参数:返回一个明确的新的坐标位置,在指定的父视图坐标系统中

简单的理解就是

该方法返回在横坐标上、纵坐标上拖动了多少像素

因为拖动起来一直是在递增,所以每次都要用setTranslation:方法制0这样才不至于不受控制般滑动出视图

 

- (CGPoint)velocityInView:(UIView *)view方法的API解释如下:


The velocity of the pan gesture in the coordinate system of the specified view.


Return Value

The velocity of the pan gesture, which is expressed in points per second. The velocity is broken into horizontal and vertical components.

字面理解:

在指定坐标系统中pan gesture拖动的速度

返回参数:返回这种速度

简单的理解就是

你拖动这个图片的时候肯定有个速度,因此返回值就是你拖动时X和Y轴上的速度,速度是矢量,有方向

- (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 旋转视图时,为什么播放器的视频会黑一下,再显示出来的?
最新发布
07-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值