// // UIView+YOUPAIRCDDanmaku.m // DanMuDemo // // Created by Sin on 16/9/26. // Copyright © 2016年 Sin. All rights reserved. // #import "UIView+YOUPAIRCDDanmaku.h" #import "YOUPAIRCDDanmaku.h" #import "YOUPAIRCDDanmakuInfo.h" #import "YOUPAIRCDDanmakuManager.h" #define X(view) view.frame.origin.x #define Y(view) view.frame.origin.y #define Width(view) view.frame.size.width #define Height(view) view.frame.size.height #define Left(view) X(view) #define Right(view) (X(view) + Width(view)) #define Top(view) Y(view) #define Bottom(view) (Y(view) + Height(view)) #define CenterX(view) (Left(view) + Right(view))/2 #define CenterY(view) (Top(view) + Bottom(view))/2 @implementation UIView (YOUPAIRCDDanmaku) #pragma mark - public method //发送一个弹幕 - (void)sendDanmaku:(YOUPAIRCDDanmaku *)danmaku { danmaku.playView.tag = RCDDanmakuViewTag; [RCDanmakuManager.danmakus addObject:danmaku]; //如果允许过量加载demo,就不进行弹幕的缓存, if(RCDanmakuManager.isAllowOverLoad){ if(!RCDanmakuManager.isPlaying) { }else { [self rc_playDanmaku:danmaku]; } }else { [self rc_playOverLoadDanmaku]; } } //发送一个特定位置的弹幕,根据point来确定弹幕左上角的位置 - (void)sendDanmaku:(YOUPAIRCDDanmaku *)danmaku atPoint:(CGPoint)point { [RCDanmakuManager.danmakus addObject:danmaku]; UIView* playerView = danmaku.playView; CGRect playViewFrame = playerView.frame; playViewFrame.origin.x = point.x; playViewFrame.origin.y = point.y; playerView.frame = playViewFrame; //确定好弹幕的位置之后发一个中心点位置的弹幕 [self sendDanmaku:danmaku atCenterPoint:playerView.center]; } //发送一个特定位置的弹幕,根据point来确定弹幕的中心点位置 - (void)sendDanmaku:(YOUPAIRCDDanmaku *)danmaku atCenterPoint:(CGPoint)point { [RCDanmakuManager.danmakus addObject:danmaku]; UIView* playerView = danmaku.playView; playerView.center = point; YOUPAIRCDDanmakuInfo *info = [[YOUPAIRCDDanmakuInfo alloc]init]; info.danmaku = danmaku; info.danmaku.playView = playerView; [self rc_checkDanmakuViewInView:playerView]; [self rc_playSpecialDanamku:info]; } //停止弹幕 - (void)youpaifstopDanmaku { RCDanmakuManager.isPlaying = NO; [RCDanmakuManager.timer invalidate]; RCDanmakuManager.timer = nil; [RCDanmakuManager.danmakus removeAllObjects]; [RCDanmakuManager.linesDict removeAllObjects]; [RCDanmakuManager.subDanmakuInfos removeAllObjects]; for(UIView *View in RCDanmakuManager.currentDanmakuCache){ [View removeFromSuperview]; } for(UIView *view in self.subviews){ if(RCDDanmakuViewTag == view.tag){ [view removeFromSuperview]; } } [RCDanmakuManager.currentDanmakuCache removeAllObjects]; [RCDanmakuManager reset]; } //暂停弹幕配合 youpaifresumeDanmaku 使用 - (void)youpaifpauseDanmaku { if(RCDanmakuManager.isAllowOverLoad){ if(!RCDanmakuManager.isPlaying) return ; }else { if(!RCDanmakuManager.timer || !RCDanmakuManager.timer.isValid ) return; } RCDanmakuManager.isPlaying = NO; [RCDanmakuManager.timer invalidate]; RCDanmakuManager.timer = nil; for (UIView* View in self.subviews) { if(RCDDanmakuViewTag == View.tag){ CALayer *layer = View.layer; CGRect rect = View.frame; if (layer.presentationLayer) { rect = ((CALayer *)layer.presentationLayer).frame; } View.frame = rect; [View.layer removeAllAnimations]; } } } //重开弹幕配合 youpaifpauseDanmaku 使用 - (void)youpaifresumeDanmaku { if( RCDanmakuManager.isPlaying )return; RCDanmakuManager.isPlaying = YES; for (YOUPAIRCDDanmakuInfo* info in RCDanmakuManager.subDanmakuInfos) { if (info.danmaku.position == RCDDanmakuPositionNone) { //计算暂停在屏幕上的弹幕的剩余时间 UIView *View = info.danmaku.playView; CGFloat scale = 1.0 * Right(View) / (Width(self) + Width(View)); NSTimeInterval duration = RCDanmakuManager.duration *scale; [self rc_performAnimationWithDuration:duration danmakuInfo:info]; }else{ [self rc_performCenterAnimationWithDuration:info.leftTime danmakuInfo:info]; } } } #pragma mark - private method - (void)rc_playDanmaku:(YOUPAIRCDDanmaku *)danmaku { NSLog(@"总弹幕数%zd",RCDanmakuManager.danmakus.count); danmaku.playView.backgroundColor = [UIColor clearColor]; switch (danmaku.position) { case RCDDanmakuPositionNone: [self rc_playFromRightDanmaku:danmaku playerView:danmaku.playView]; break; case RCDDanmakuPositionCenterTop: case RCDDanmakuPositionCenterBottom: [self rc_playCenterDanmaku:danmaku playerView:danmaku.playView]; break; default: break; } } #pragma mark over load danmaku - (void)rc_playOverLoadDanmaku { if (!RCDanmakuManager.timer && RCDanmakuManager.isPlaying) { NSTimeInterval interval = RCDanmakuManager.duration / RCDanmakuManager.maxShowLineCount * 1.0 + 0.1; RCDanmakuManager.timer = [NSTimer timerWithTimeInterval:interval target:self selector:@selector(rc_sendOverLoadDanmaku) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:RCDanmakuManager.timer forMode:NSRunLoopCommonModes]; [RCDanmakuManager.timer fire]; } } - (void)rc_sendOverLoadDanmaku { if(RCDanmakuManager.danmakus.count > 0){ NSLog(@"count total %zd",RCDanmakuManager.danmakus.count); [self rc_playDanmaku:RCDanmakuManager.danmakus[0]]; [RCDanmakuManager.danmakus removeObjectAtIndex:0]; } } #pragma mark center top \ bottom - (void)rc_playCenterDanmaku:(YOUPAIRCDDanmaku *)danmaku playerView:(UIView *)playerView { NSAssert(RCDanmakuManager.centerDuration && RCDanmakuManager.maxCenterLineCount, @"如果要使用中间弹幕 必须先设置中间弹幕的时间及最大行数"); YOUPAIRCDDanmakuInfo* newInfo = [[YOUPAIRCDDanmakuInfo alloc] init]; newInfo.danmaku.playView = playerView; newInfo.leftTime = RCDanmakuManager.centerDuration; newInfo.danmaku = danmaku; NSMutableDictionary* centerDict = nil; if (danmaku.position == RCDDanmakuPositionCenterTop) { centerDict = RCDanmakuManager.centerTopLinesDict; }else{ centerDict = RCDanmakuManager.centerBottomLinesDict; } NSInteger valueCount = centerDict.allKeys.count; if (valueCount == 0) { newInfo.lineCount = 0; [self rc_addCenterAnimation:newInfo centerDict:centerDict]; return; } for (int i = 0; iselectingList.count-1) { index = selectingList.count-1; } return [selectingList[index] integerValue]; } - (void)rc_addAnimationToViewWithInfo:(YOUPAIRCDDanmakuInfo *)info { UIView* View = info.danmaku.playView; NSInteger lineCount = info.lineCount; NSInteger heigth = KScreenHeight / 2; CGFloat y = arc4random() % heigth + heigth - Height(View) - SafeHeight; //(RCDanmakuManager.lineHeight + RCDanmakuManager.lineMargin) * lineCount, View.frame = CGRectMake(Width(self), y, Width(View), Height(View)); [RCDanmakuManager.subDanmakuInfos addObject:info]; RCDanmakuManager.linesDict[@(lineCount)] = info; [self rc_performAnimationWithDuration:info.leftTime danmakuInfo:info]; } - (void)rc_performAnimationWithDuration:(NSTimeInterval)duration danmakuInfo:(YOUPAIRCDDanmakuInfo *)info { RCDanmakuManager.isPlaying = YES; UIView* View = info.danmaku.playView; CGRect endFrame = CGRectMake(-Width(View), Y(View), Width(View), Height(View)); [self addSubview:View]; __weak typeof(self) weakSelf = self; [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ View.frame = endFrame; } completion:^(BOOL finished) { if (finished) { [weakSelf rc_removeDanmakuInfoAfterAnimation:info]; [RCDanmakuManager.linesDict removeObjectForKey:@(info.lineCount)]; NSLog(@"count left %zd",RCDanmakuManager.danmakus.count); } }]; } #pragma mark util method //播放特定位置的弹幕的动画 - (void)rc_playSpecialDanamku:(YOUPAIRCDDanmakuInfo *)info { UIView *View = info.danmaku.playView; [RCDanmakuManager.currentDanmakuCache addObject:View]; [self addSubview:View]; __weak typeof(self) weakSelf = self; NSTimeInterval duration = RCDanmakuManager.specialDuration; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ if(!RCDanmakuManager.isPlaying) return ; [weakSelf rc_removeDanmakuInfoAfterAnimation:info]; }); } //一个弹幕消失之后,将其彻底移除 - (void)rc_removeDanmakuInfoAfterAnimation:(YOUPAIRCDDanmakuInfo *)info { UIView *View = info.danmaku.playView; [View removeFromSuperview]; [RCDanmakuManager.danmakus removeObject:info.danmaku]; [RCDanmakuManager.currentDanmakuCache removeObject:View]; [RCDanmakuManager.subDanmakuInfos removeObject:info]; info = nil; } //检测特定位置弹幕是否是在视频页面中 - (void)rc_checkDanmakuViewInView:(UIView *)View { if(!CGRectContainsRect(self.frame, View.frame)){ NSLog(@"warning : 特殊点弹幕的位置超出可视范围"); } } @end