弹幕的实现

2017-07-02  本文已影响0人  星星点灯0_0

前言

随着视频直播类app的崛起,为了增加用户的粘性以及趣味性,弹幕越来越受到视频类应用或者网站的青睐,下面是两种最常见的弹幕效果


弹幕.jpg
弹幕3.jpg

做为一个开发人员,看到这些酷炫的效果,有时候也难免会想一下这个是怎么实现的?
下面我们来分析一下这种实现
1.弹幕从右往左按照一定的轨迹移动
2.弹幕文字的内容长短不一需要计算
3.一个弹幕进入不久,另外一个弹幕紧接着要进入
4.停止时,需要清空数据,移除弹幕

技术实现:
弹幕可以写一个View类,上面可以添加Lable直接显示文字

1.弹幕移动时,我们需要计算弹幕需要移动的整个距离,计算弹幕运行的速度,并且文字越长运行的速度越快

  //根据定义的duration计算速度
    CGFloat wholeWidth = CGRectGetWidth(self.frame) + kWidth + 50;
    CGFloat speed = wholeWidth/Duration;
    //以及完全进入屏幕的时间
    CGFloat dur = (CGRectGetWidth(self.frame) + 50)/speed;
    
    
    __block CGRect frame = self.frame;
    if (self.moveBlock) {
        //弹幕开始进入屏幕
        self.moveBlock(Start);
    }
    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(dur * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        //避免重复,通过变量判断是否已经释放了资源,释放后,不在进行操作
        if (self.bDealloc) {
            return;
        }
        //dur时间后弹幕完全进入屏幕
        if (self.moveBlock) {
            self.moveBlock(Enter);
        }
    });
    
    //弹幕动画移动,出了屏幕后从父视图上移除
    [UIView animateWithDuration:Duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
        frame.origin.x = -CGRectGetWidth(frame);
        self.frame = frame;
    } completion:^(BOOL finished) {
        if (self.moveBlock) {
            self.moveBlock(End);
        }
        [self removeFromSuperview];
    }];

2.创建弹幕,处理弹幕在不同状态下的逻辑,这三总状态分别是弹幕开始,弹幕完全进入屏幕,弹幕完全离开屏幕

 //创建一个弹幕view
    BulletView *view = [[BulletView alloc] initWithContent:comment];
    //设置运行轨迹
    view.trajectory = trajectory;
    __weak BulletView *weakBulletView = view;
    __weak BulletManager *myself = self;
      view.moveBlock = ^(CommentMoveStatus status) {
        if (myself.bStopAnimation) {
            return ;
        }
        switch (status) {
            case Start:
                //弹幕开始……将view加入弹幕管理queue
                [self.bulletQueue addObject:weakBulletView];
                break;
            case Enter: {
                //弹幕完全进入屏幕,判断接下来是否还有内容,如果有则在该弹道轨迹对列中创建弹幕……
                NSString *comment = [myself nextComment];
                if (comment) {
                    [myself createBulletComment:comment trajectory:trajectory];
                } else {
                    //说明到了评论的结尾了
                }
                break;
            }
            case End: {
                //弹幕飞出屏幕后从弹幕管理queue中删除
                if ([myself.bulletQueue containsObject:weakBulletView]) {
                    [myself.bulletQueue removeObject:weakBulletView];
                }
                if (myself.bulletQueue.count == 0) {
                    //说明屏幕上已经没有弹幕评论了,循环开始
                    [myself start];
                }

3.当需要弹幕的时候初始化n条弹幕轨迹,我这里初始化3条,每展示一天弹幕,则从本地集合中删除展示的数据,直到所有的数据展示完

    NSMutableArray *arr = [NSMutableArray arrayWithArray:@[@(0), @(1), @(2)]];
    for (int i = 3; i > 0; i--) {
        NSString *comment = [self.tmpComments firstObject];
        if (comment) {
            [self.tmpComments removeObjectAtIndex:0];
            //随机生成弹道创建弹幕进行展示(弹幕的随机飞入效果)
            NSInteger index = arc4random()%arr.count;
            Trajectory trajectory = [[arr objectAtIndex:index] intValue];
            [arr removeObjectAtIndex:index];
            [self createBulletComment:comment trajectory:trajectory];
        } else {
            //当弹幕小于三个,则跳出
            break;
        }
    }

4.如果我们想要从弹幕父视图上查找被点击的视图,我们只需要给self.view添加手势,然后根据手势坐落在弹幕背景视图上的位置,可以查找出被点击的弹幕,从而获得弹幕上的内容

    CGPoint clickPoint =  [gesture locationInView:self];
    BulletView *bulletView = [self findClickBulletView:clickPoint];
    - (BulletView *)findClickBulletView:(CGPoint)point {
    BulletView *bulletView = nil;
    for (UIView *v in [self subviews]) {
        if ([v isKindOfClass:[BulletView class]]) {
            if ([v.layer.presentationLayer hitTest:point]) {
                bulletView = (BulletView *)v;
                break;
            }
        }
    }
    return bulletView;
}

![我的弹幕.png](https://img.haomeiwen.com/i5423128/9a366210619afe83.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

至此,大体功能上是实现了,但是要是面对直播中各种形形色色的弹幕,那肯定还是不够的,这里的demo仅供参考,如有需要,请戳这里~

上一篇 下一篇

猜你喜欢

热点阅读