123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402 |
- //
- // 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; i<valueCount; i++) {
- YOUPAIRCDDanmakuInfo* oldInfo = centerDict[@(i)];
- if (!oldInfo) break;
- if (![oldInfo isKindOfClass:[YOUPAIRCDDanmakuInfo class]]) {
- newInfo.lineCount = i;
- [self rc_addCenterAnimation:newInfo centerDict:centerDict];
- break;
- }else if (i == valueCount - 1){
- if (valueCount < RCDanmakuManager.maxCenterLineCount) {
- newInfo.lineCount = i+1;
- [self rc_addCenterAnimation:newInfo centerDict:centerDict];
- }else{
- [self rc_removeDanmakuInfoAfterAnimation:newInfo];
- NSLog(@"同一时间评论太多--排不开了--------------------------");
- }
- }
- }
-
- }
- - (void)rc_addCenterAnimation:(YOUPAIRCDDanmakuInfo *)info centerDict:(NSMutableDictionary *)centerDict
- {
-
- UIView* View = info.danmaku.playView;
- NSInteger lineCount = info.lineCount;
-
- if (info.danmaku.position == RCDDanmakuPositionCenterTop) {
- View.frame = CGRectMake((Width(self) - Width(View)) * 0.5, (RCDanmakuManager.lineHeight + RCDanmakuManager.lineMargin) * lineCount, Width(View), Height(View));
- NSLog(@"top frame %@",NSStringFromCGRect(View.frame));
- }else{
- View.frame = CGRectMake((Width(self) - Width(View)) * 0.5, Height(self) - Height(View) - (RCDanmakuManager.lineHeight + RCDanmakuManager.lineMargin) * lineCount, Width(View), Height(View));
- NSLog(@"bottom frame %@",NSStringFromCGRect(View.frame));
- }
-
- centerDict[@(lineCount)] = info;
- [RCDanmakuManager.subDanmakuInfos addObject:info];
-
- [self rc_performCenterAnimationWithDuration:info.leftTime danmakuInfo:info ];
- }
- - (void)rc_performCenterAnimationWithDuration:(NSTimeInterval)duration danmakuInfo:(YOUPAIRCDDanmakuInfo *)info
- {
- UIView* View = info.danmaku.playView;
- [RCDanmakuManager.currentDanmakuCache addObject:View];
-
- NSLog(@"index %zd",info.lineCount);
-
- [self addSubview:View];
- __weak typeof(self) weakSelf = self;
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- if(!RCDanmakuManager.isPlaying) return ;
-
- if (info.danmaku.position == RCDDanmakuPositionCenterBottom) {
- RCDanmakuManager.centerBottomLinesDict[@(info.lineCount)] = @(0);
- }else{
- RCDanmakuManager.centerTopLinesDict[@(info.lineCount)] = @(0);
- }
- [weakSelf rc_removeDanmakuInfoAfterAnimation:info];
- });
- }
- #pragma mark from right
- - (void)rc_playFromRightDanmaku:(YOUPAIRCDDanmaku *)danmaku playerView:(UIView *)playerView
- {
-
- YOUPAIRCDDanmakuInfo* newInfo = [[YOUPAIRCDDanmakuInfo alloc] init];
- newInfo.danmaku.playView = playerView;
- newInfo.leftTime = RCDanmakuManager.duration;
- newInfo.danmaku = danmaku;
- [RCDanmakuManager.currentDanmakuCache addObject:playerView];
-
- NSMutableArray *arr = [self rc_getNSArray];
- NSArray *lineArr = RCDanmakuManager.linesDict.allKeys;
- [arr removeObjectsInArray:lineArr];
- NSInteger lineCount = [self rc_getRandomNum:arr];
- if(!RCDanmakuManager.isAllowOverLoad) {
- newInfo.lineCount = lineCount;
- while (1) {
- YOUPAIRCDDanmakuInfo* oldInfo = RCDanmakuManager.linesDict[@(newInfo.lineCount)];
- if(oldInfo){
- NSInteger randNum = [self rc_getRandomNum:arr];
- NSLog(@"----------------------------------");
- newInfo.lineCount = randNum*randNum % RCDanmakuManager.maxShowLineCount;
- }else{
- break;
- }
- }
- }else {
- lineCount = abs((int)arc4random()) % RCDanmakuManager.maxShowLineCount;
- newInfo.lineCount = lineCount;
- }
-
- playerView.frame = CGRectMake(Width(self), 0, Width(playerView), Height(playerView));
-
- [self rc_addAnimationToViewWithInfo:newInfo];
-
- }
- - (NSMutableArray *)rc_getNSArray {
- NSMutableArray *arr = [NSMutableArray new];
- arr = [NSMutableArray new];
- for (int i=0;i<RCDanmakuManager.maxShowLineCount;i++){
- [arr addObject:@(i)];
- }
- return arr;
- }
- - (NSInteger)rc_getRandomNum:(NSArray *)selectingList{
-
- if(selectingList.count == 0){
- return 0;
- }
- NSInteger index = arc4random_uniform((u_int32_t)selectingList.count-1);
- if(index<0){
- index = 0;
- }else if(index >selectingList.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
|