BarrageKit弹幕插件

作者: ManoBoo | 来源:发表于2016-09-13 16:12 被阅读744次

BarrageKit弹幕插件


前言


现在直播这么火,好多直播框架,诸如IJKMediaFramework等更是方便了直播类APP的开发,那我们也一起给它添砖加瓦吧。

插件介绍


插件是基于Objective-C编写的,整体思路较为简单,功能包括:

  1. 弹幕的滚动方向、滚动速度
  2. 弹幕的暂停与恢复、显示与隐藏
  3. 弹幕的类型:纯文字弹幕、投票类弹幕、其他等(可自定义)
  4. 弹幕的推送方式:主动获取弹幕源、被动接收
  5. 弹幕的缓存,避免大量弹幕出现时内存Boom

还有一些不完善的地方(比如弹幕的轨道现为随机生成,可能会重叠)及一些新的功能欢迎issue

插件展示


  • 四个方向的弹幕滚动
四个方向的弹幕滚动
  • 弹幕的暂停与恢复


    弹幕的暂停与恢复

核心代码介绍


BarrageManager弹幕管理者

数组介绍:

  • _cachePool为弹幕单元的缓冲数组,从屏幕上移除的BarrageScene会加入到该数组中
  • _barrageScene为当前屏幕上正在显示的弹幕显示单元的数组,弹幕显示的时候会加入到该数组中

BarrageManager 作为弹幕的管理者,流程为:

  • 初始化弹幕manager,启动timer,主动拉取弹幕数据,调用-delegate barrageManagerDataSource返回数据。
  • 调用- (void)showWithData:(id)data方法显示弹幕,data可以为BarrageModelNSArray格式
    • 判断缓冲池是否为空,为空则新建弹幕显示单元BarrageScene,并加入到_barrageScene数组中。若不为空,则取出_cachePoolfirstObject进行重用并从_cachePool中移除,添加到_barrageScene中来

核心代码如下:

if (_cachePool.count < 1) {
                    // nil
                    BarrageScene *scene = [[BarrageScene alloc] initWithFrame:CGRectZero Model:model];
                    [_barrageScene addObject:scene];
                    [_bindingView addSubview:scene];
                    Weakself;
                    scene.animationDidStopBlock = ^(BarrageScene *scene_){
                        [weakSelf.cachePool addObject:scene_];
                        [weakSelf.barrageScene removeObject:scene_];
                        [scene_ removeFromSuperview];
                    };
                    [scene scroll];
                    
                }else {
                    //从缓冲池获取到Scene后,将其从缓冲池中移除
//                    NSLog(@"get from cache");
                    BarrageScene *scene =  _cachePool.firstObject;
                    [_barrageScene addObject:scene];
                    [_cachePool removeObjectAtIndex:0];
                    scene.model = model;
                    
                    [_bindingView addSubview:scene];
                    [scene scroll];
                }

BarrageModel弹幕模型

message弹幕信息为NSMutableAttributedString类型,图片、表情等都可以使用了

模型属性:

//弹幕ID barrage's id
@property (assign, nonatomic) NSInteger numberID;

//弹幕时间 barrage;s time
@property (strong, nonatomic) NSString *time;

//弹幕类型 barrage's type
@property (assign, nonatomic) BarrageDisplayType barrageType;

//弹幕速度 barrage's speed
@property (assign, nonatomic) BarrageDisplaySpeedType speed;

//弹幕滚动方向 barrage's direction
@property (assign, nonatomic) BarrageScrollDirection direction;

//弹幕位置 barage's location
@property (assign, nonatomic) BarrageDisplayLocationType displayLocation;

//弹幕所属的父View  barrage's superView
@property (weak, nonatomic) UIView *bindView;

//弹幕内容 barrage's content
@property (strong, nonatomic, nonnull) NSMutableAttributedString *message;

//弹幕作者 barrage's author
@property (strong, nonatomic, nullable) id author;

//弹幕对象 goal object
@property (strong, nonatomic, nullable) id object;

//弹幕字体 barrage's textfont
@property (copy, nonatomic) UIFont *font;

//弹幕字体颜色 barrage's textColor
@property (copy, nonatomic) UIColor *textColor;

BarrageScene弹幕显示单元

  • 滚动Scroll

  • ①根据弹幕的滚动速度和滚动方向计算弹幕的滚动距离和所需要的时间

  • ②使用CABasicAnimation完成动画,后期弹幕的暂停和回复比较方便

  • ③弹幕滚动完毕后,执行_animationDidStopBlock,将该scene加入到managercachePool中等待被重用

  • 重用

  • 弹幕从BarrageManagercachePool中取出来,根据BarrageModel弹幕信息重新初始化frame且重新开始动画

  • 暂停 pause

    • 暂停layer动画即可
CFTimeInterval pausedTime = [self.layer convertTime:CACurrentMediaTime() fromLayer:nil];
self.layer.speed = 0.0;
self.layer.timeOffset = pausedTime;
  • 恢复 resume
    • 恢复layer动画即可
CFTimeInterval pausedTime = [self.layer timeOffset];
self.layer.timeOffset = 0.0;
self.layer.beginTime = 0.0;
self.layer.speed = 1.0;
CFTimeInterval timeSincePause = [self.layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
self.layer.beginTime = timeSincePause;
  • 关闭 close
[self.layer removeAllAnimations];
[self removeFromSuperview];

插件使用

下载项目导入到项目中,使用时import 'BarrageKit.h'即可

_manager = [BarrageManager manager];
    
    //出现的View
    _manager.bindingView = self.view;
    
    //delegate
    _manager.delegate = self;
    
    //弹幕显示位置
    _manager.displayLocation = BarrageDisplayLocationTypeDefault;
    
    //滚动方向
    _manager.scrollDirection = BarrageScrollDirectRightToLeft;
    
    //滚动速度
    _manager.scrollSpeed = 30;
    
    //收到内存警告的处理方式
    _manager.memoryMode = BarrageMemoryWarningModeHalf;
    
    //刷新时间
    _manager.refreshInterval = 1.0;
    
    //开始滚动 manager主动获取弹幕,另外一种方式,`[_manager showBarrageWithDataSource:m]` 退出弹幕即可
    [_manager startScroll];

Tips:

  • ①如果弹幕为投票类型的弹幕时,请重写ViewControllertouchesBegan 方法
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    UITouch *touch = [touches anyObject];
    CGPoint touchPoint = [touch locationInView:self.view];
    [[_manager barrageScenes] enumerateObjectsUsingBlock:^(BarrageScene * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj.layer.presentationLayer hitTest:touchPoint]) {
            //弹幕类型为投票类型时,为弹幕添加点击事件,请在此处添加
            /* if barrage's type is ` BarrageDisplayTypeVote `, add your code here*/
            NSLog(@"message = %@",obj.model.message.string);
        }
    }];
}
  • ②重写ViewControllerdealloc方法,执行BarrageManagertoDealloc
  • ③ViewController收到内存警告时,[_manager didReceiveMemoryWarning];将会按照memoryMode指定的方法清楚缓冲池
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    
    // 收到内存警告时,清楚弹幕缓冲池 When you receive a memory warning,clean the barrage's cache
    [_manager didReceiveMemoryWarning];
}
  • ④如果要高度自定义弹幕显示,可以修改BarrageScene中的初始化代码

最后

大家查看项目后,欢迎issue,同时有其他的功能或建议欢迎提出来,简书、github均可。

相关文章

网友评论

  • 敢去做:你好 请问在 -(id)barrageManagerDataSource{
    NSArray *testArray = [NSArray arrayWithObjects:@"测试1111",@" 测试2222",@"测试3333",@"测试4444" ,nil];
    }方法里面怎么显示数组内容呢!
    ManoBoo:额 这个需求比较奇特,不过你可以用delegate那种方式每次都返回固定的弹幕,也能实现你的需求,因为目前代码中的动画都是直接计算好写死的
    敢去做:@ManoBoo 请问 showBarrageWithDataSource 方法可以实现无限滚动的弹幕吗? 有那个属性可以设置吗? 我试了只可以滚动一遍
    ManoBoo:@敢去做 这个delegate是 弹幕resource 主动定时调用的代理方法
    如果想要手动显示一个弹幕数组
    manager showBarrageWithDataSource: 这个方法
  • c19dfb62786e:很给力~~
  • c19dfb62786e:大神 那个弹幕位置好像没有效果 另外这样随机轨迹有很大几率会重叠在一起有神马解决方案吗
    ManoBoo:@我会做梦啊啊啊啊 Scene 类里面,有一个随机返回frame的方法,改掉即可,我重构下代码吧~
    c19dfb62786e:@ManoBoo 好的,我试下。 那个弹幕位置我怎么设置都是全屏随机位置额:relaxed:
    ManoBoo:提供一种解决方案:
    按屏幕高度 计算有多少条轨道,每次show弹幕的时候,选择一条即可
  • VoiderSun:问一下恢复layer动画为什么我的弹幕就消失了
    ManoBoo:暂停Layer动画OK嘛?
    VoiderSun:@ManoBoo 自定义的
    ManoBoo:是指我项目中的Demo吗 还是自定义的:blush:
  • AIlls:从上往下滚动的和从上往下滚动的有些弹幕显示不全。。。 originPoint = CGPointMake(RandomBetween(0, CGRectGetWidth(sourceFrame)), CGRectGetMaxY(sourceFrame) + CGRectGetHeight(self.bounds));改为 originPoint = CGPointMake(RandomBetween(0, CGRectGetWidth(sourceFrame) - self.frame.size.width), CGRectGetMaxY(sourceFrame) + CGRectGetHeight(self.bounds)); 保证x的随机值一定能让弹幕能显示全。。。 :grin: 你看看是不是对的。。。。
    ManoBoo:@AIlls 客气客气 给你回复的时候 显示@Alls 我还以为是所有人。。 来回看了半天 原来你的昵称是Alls 。。。。。
    AIlls:@ManoBoo :+1:不用谢。。大神。。。 我还要多向你学习呢,,, :+1: :+1:
    ManoBoo:@AIlls 恩 是的 从上往下 忘了改这个 thanks :smile:
  • qBryant:叼叼的~~~! :+1:
    qBryant:@ManoBoo ok
    ManoBoo:@QBryant :smile: 谢谢,功能暂时只有弹幕,有什么好的建议给我告诉我
  • BeijingIamback:nice
    ManoBoo:@BeijingIamback 功能比较简单,谢谢捧场~
  • pidano:占楼编辑~
    ManoBoo:@Sunnyzx 给钱了吗?
    :smile:

本文标题:BarrageKit弹幕插件

本文链接:https://www.haomeiwen.com/subject/zfmmettx.html