弹幕效果实现

Fuck the world if you are rich,otherwise fuck youself.

前言

昨天晚上11点了还没睡着,惆怅能力不足,但不知道怎么能快速的提升自己。呜呼哀哉,临睡前看了一个弹幕的效果实现的技术视频,听着很好的,自己在做电商这块也没写过弹幕。今天来到公司趁着闲暇按照人家说的思路写了一下,有用得上的可以看看。
demo地址

正文

先来看一下最终实现的效果:

Simulator Screen Shot 2016年7月27日 下午1.46.11.png

在这里,我只说一下重要的思想和代码块部分,关于其他的不再细说。代码很简单,基本上跑一下在瞅瞅就理解的差不多了。

思想

弹幕说白了就是移动的label.创建一个view里装着label用于做移动使用。view,label的宽度根据字体的多少去改变。然后开始移动,改变view的x值的大小。当view完全移除屏幕的时候这条弹幕完成,把view移除,开始下一条。

核心代码

装着label的view

首先构造方法不能少的

//创建
- (instancetype)initWithComment:(NSString *)comment{

    self = [super init];
    if (self) {
        //创建label
        self.commentLabel.text = comment;
        NSDictionary *attr = @{NSFontAttributeName:[UIFont systemFontOfSize:14]};
        CGFloat width = [comment sizeWithAttributes:attr].width;//求出字体的宽度
        self.bounds = CGRectMake(0, 0, width + 2 * padding, 30);
        self.commentLabel.frame = CGRectMake(padding, 0, width, 30);
    }
    return self;
}

构造里面有label的frame确定,那我们内存空间一定要有label才可以,这里才用懒加载的方式创建label

//创建label
- (UILabel *)commentLabel{

    if (!_commentLabel) {
        _commentLabel = [[UILabel alloc]initWithFrame:self.bounds];
        _commentLabel.backgroundColor = [UIColor redColor];
        _commentLabel.textColor = [UIColor whiteColor];
        _commentLabel.font = [UIFont systemFontOfSize:14];
        _commentLabel.textAlignment = NSTextAlignmentCenter;
        _commentLabel.layer.cornerRadius = 5;
        _commentLabel.layer.masksToBounds = YES;
        [self addSubview:_commentLabel];
    }
    return _commentLabel;
}

然后开始弹幕动画的实现

#pragma mark -------开始结束方法
//开始方法
- (void)startAnimation{

    //给出uilabel的位置大小
    CGFloat screen = [UIScreen mainScreen].bounds.size.width;
    CGFloat duration = 3.0f;
    CGFloat wholeWidth = screen + CGRectGetWidth(self.bounds);
    
    //开始
    if (self.successShowComment) {
        self.successShowComment(syf_start);
    }
    
    //运行时间
    CGFloat speed = wholeWidth / 3.0f;
    CGFloat enterDurtion = CGRectGetWidth(self.bounds) / speed;
    [self performSelector:@selector(p_enterScreen) withObject:self afterDelay:enterDurtion];
    
    __block CGRect frame = self.frame;
    [UIView animateWithDuration:duration animations:^{
        
        frame.origin.x -= wholeWidth;
        self.frame = frame;
    } completion:^(BOOL finished) {
        [self removeFromSuperview];
        
        if (self.successShowComment) {
            self.successShowComment(syf_end);
        }
    }];
}
//结束
- (void)stopAnimation{
    
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    [self.layer removeAllAnimations];
    [self removeFromSuperview];
}

#pragma mark -------私有方法
//view尾部也进入屏幕后调用
- (void)p_enterScreen{

    if (self.successShowComment) {
        self.successShowComment(syf_enter);
    }
}

为了逻辑清晰,以后代码好维护。我们才用了一个manager类区管理弹幕的方法实现,而不直接去vc里面写。
首先创建三个数组,分别去存弹幕view,原始数据,和数据处理数组

@property(nonatomic,strong)NSMutableArray *commentArray;//数据数组
@property(nonatomic,strong)NSMutableArray *barrageViews;//弹幕数组
@property(nonatomic,strong)NSMutableArray *barrageComment;//处理数组
@property(nonatomic,assign)BOOL stopAnimation;//判断开始还是停止状态

然后就是管理弹幕开始移动和停止的方法

#pragma mark -----开始停止方法
//开始
- (void)start{

    if (!self.stopAnimation) {
        return;
    }
    self.stopAnimation = NO;
    
    //数组数据全部移除
    [self.barrageComment removeAllObjects];
    [self.barrageComment addObjectsFromArray:self.commentArray];
    [self p_initBarrageComment];
    

}
//停止
- (void)stop{
    if (self.stopAnimation) {
        return;
    }
    self.stopAnimation = YES;
    if (self.barrageViews.count > 0) {
        
        [self.barrageViews enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            SYFBarrageView *view = obj;
            [view stopAnimation];
            view = nil;
        }];
        
        [self.barrageViews removeAllObjects];
    }
    
}

底下的代码块是核心的操作代码:
基本思路就是看你需要创建几个同时移动的弹幕,我这里选择了5个,然后随机选择每个弹道去放弹幕,当一个弹幕的尾部也出现到屏幕时,就检查是否还有没有显示的弹幕内容,如果有,在这个弹道显示没有显示的弹幕内容。

#pragma mark ------私有方法
- (void)p_initBarrageComment{

    NSMutableArray *tempArray = [NSMutableArray arrayWithObjects:@(0),@(1),@(2),@(3),@(4), nil];
    for(int i = 0;i < 5;i ++){
    
        if (self.barrageComment.count > 0 ) {
            
            //随机数
            NSInteger index = arc4random() % tempArray.count;
            int temp = [[tempArray objectAtIndex:index] intValue];
            [tempArray removeObjectAtIndex:index];
            
            //从弹幕数组逐一取出数据
            NSString *comment = [self.barrageComment firstObject];
            [self.barrageComment removeObjectAtIndex:0];
            
            //创建view
            [self p_createViewBarrageView:comment temp:temp];
        }
       
    }
}
//创建弹幕
- (void)p_createViewBarrageView:(NSString *)comment temp:(int)tempIndex{

    if (self.stopAnimation) {
        return;
    }
    SYFBarrageView *barrageView = [[SYFBarrageView alloc]initWithComment:comment];
    barrageView.tempIndex = tempIndex;
    
    
    __block typeof(self)weakSelf =self;
    __block typeof(SYFBarrageView *)weakView = barrageView;
    //移除屏幕
    barrageView.successShowComment = ^(NSInteger status){
       
        if (weakSelf.stopAnimation) {//防止在停止时被调用
            return ;
        }
        switch (status) {
            case syf_start:{
                //弹幕进入
                [weakSelf.barrageViews addObject:weakView];
            }
                break;
            case syf_enter:{
                //是否还有其他内容有,在该轨迹创建一个
                NSString *nextComment = [weakSelf p_nextComment];
                if (nextComment) {
                    [weakSelf p_createViewBarrageView:nextComment temp:tempIndex];
                }
            }
                break;
            case syf_end:
            {
                //弹幕飞出从数组删除
                if ([weakSelf.barrageViews containsObject:weakView]) {
                    [weakView stopAnimation];
                    [weakSelf.barrageViews removeObject:weakView];
                }
                
                if (weakSelf.barrageViews.count == 0) {//没有数据源了
                    weakSelf.stopAnimation = YES;
                    [weakSelf start];
                    
                }
            }
                
                break;
                
            default:
                break;
        }
    
    };
    
    
    if (self.generateViewBlock) {
        self.generateViewBlock(barrageView);
    }
    [barrageView startAnimation];
}
//是否还有弹幕
- (NSString *)p_nextComment{

    if (self.barrageComment.count == 0) {
        return  nil;
    }
    NSString *comment = [self.barrageComment firstObject];
    
    if (comment) {
        [self.barrageComment removeObjectAtIndex:0];
    }
    return comment;
}

结语

好了,感觉还是看源码好理解,有问题的可以联系我。有能力的感觉对你有点用的就给个星星,谢了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,448评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,019评论 4 62
  • 初次接触这本书是被人推荐,只知道一个人收到二十年没见并且身患癌症的朋友的一封信,为的是这样能治好她的癌症,他徒步去...
    嗯在进步阅读 327评论 0 2
  • “静”这个字可以组成很多词语。内心感觉安稳时是“宁静”;图书馆里带给我的是“安静”;独自深夜下班回家的路上是“寂静...
    远逝之风yuki阅读 505评论 2 1
  • 七夕!传说牛郎与织女见面的日子...到了现代被定义为中国式情人节。谈到情人节!大家最先想到应该是玫瑰花和德...
    三毛谷潍榕阅读 309评论 0 1