BarrageKit彈幕插件
前言
現(xiàn)在直播這么火,好多直播框架,諸如IJKMediaFramework等更是方便了直播類APP的開發(fā),那我們也一起給它添磚加瓦吧。
插件介紹
插件是基于Objective-C編寫的,整體思路較為簡單,功能包括:
- 彈幕的滾動方向、滾動速度
- 彈幕的暫停與恢復(fù)、顯示與隱藏
- 彈幕的類型:純文字彈幕、投票類彈幕、其他等(可自定義)
- 彈幕的推送方式:主動獲取彈幕源、被動接收
- 彈幕的緩存,避免大量彈幕出現(xiàn)時內(nèi)存Boom
還有一些不完善的地方(比如彈幕的軌道現(xiàn)為隨機(jī)生成,可能會重疊)及一些新的功能歡迎issue
插件展示
- 四個方向的彈幕滾動

四個方向的彈幕滾動
-
彈幕的暫停與恢復(fù)
彈幕的暫停與恢復(fù)
核心代碼介紹
①BarrageManager彈幕管理者
數(shù)組介紹:
-
_cachePool為彈幕單元的緩沖數(shù)組,從屏幕上移除的BarrageScene會加入到該數(shù)組中 -
_barrageScene為當(dāng)前屏幕上正在顯示的彈幕顯示單元的數(shù)組,彈幕顯示的時候會加入到該數(shù)組中
BarrageManager 作為彈幕的管理者,流程為:
- 初始化彈幕manager,啟動
timer,主動拉取彈幕數(shù)據(jù),調(diào)用-delegate barrageManagerDataSource返回數(shù)據(jù)。 - 調(diào)用
- (void)showWithData:(id)data方法顯示彈幕,data可以為BarrageModel或NSArray格式- 判斷緩沖池是否為空,為空則新建彈幕顯示單元
BarrageScene,并加入到_barrageScene數(shù)組中。若不為空,則取出_cachePool的firstObject進(jìn)行重用并從_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;
//彈幕內(nèi)容 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
①根據(jù)彈幕的滾動速度和滾動方向計算彈幕的滾動距離和所需要的時間
②使用CABasicAnimation完成動畫,后期彈幕的暫停和回復(fù)比較方便
③彈幕滾動完畢后,執(zhí)行
_animationDidStopBlock,將該scene加入到manager的cachePool中等待被重用重用
彈幕從
BarrageManager的cachePool中取出來,根據(jù)BarrageModel彈幕信息重新初始化frame且重新開始動畫-
暫停 pause
- 暫停layer動畫即可
CFTimeInterval pausedTime = [self.layer convertTime:CACurrentMediaTime() fromLayer:nil];
self.layer.speed = 0.0;
self.layer.timeOffset = pausedTime;
- 恢復(fù) resume
- 恢復(fù)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;
- 關(guān)閉 close
[self.layer removeAllAnimations];
[self removeFromSuperview];
插件使用
下載項目導(dǎo)入到項目中,使用時import 'BarrageKit.h'即可
_manager = [BarrageManager manager];
//出現(xiàn)的View
_manager.bindingView = self.view;
//delegate
_manager.delegate = self;
//彈幕顯示位置
_manager.displayLocation = BarrageDisplayLocationTypeDefault;
//滾動方向
_manager.scrollDirection = BarrageScrollDirectRightToLeft;
//滾動速度
_manager.scrollSpeed = 30;
//收到內(nèi)存警告的處理方式
_manager.memoryMode = BarrageMemoryWarningModeHalf;
//刷新時間
_manager.refreshInterval = 1.0;
//開始滾動 manager主動獲取彈幕,另外一種方式,`[_manager showBarrageWithDataSource:m]` 退出彈幕即可
[_manager startScroll];
Tips:
- ①如果彈幕為投票類型的彈幕時,請重寫
ViewController的touchesBegan方法
- (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);
}
}];
}
- ②重寫
ViewController的dealloc方法,執(zhí)行BarrageManager的toDealloc - ③ViewController收到內(nèi)存警告時,
[_manager didReceiveMemoryWarning];將會按照memoryMode指定的方法清楚緩沖池
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
// 收到內(nèi)存警告時,清楚彈幕緩沖池 When you receive a memory warning,clean the barrage's cache
[_manager didReceiveMemoryWarning];
}
- ④如果要高度自定義彈幕顯示,可以修改
BarrageScene中的初始化代碼
