版本记录
版本号 | 时间 |
---|---|
V1.0 | 2017.07.23 |
前言
在我们做直播等视频类app的时候,总是有显示和发送弹幕的要求,弹幕可以方便用户进行沟通和互动,增加了娱乐性,增强app等客户端的用户粘度,下面我们就说一下弹幕显示方面的问题和相关框架BarrageRenderer。
1. 直播中BarrageRenderer弹幕的显示(一)—— 框架介绍
这一篇就结合工程实现说明该框架的使用。
BarrageRenderer文件
下面看一下这个头文件。
#import <Foundation/Foundation.h>
#import "BarrageHeader.h"
@class BarrageDescriptor;
@class BarrageRenderer;
@protocol BarrageRendererDelegate <NSObject>
@optional
/// 通过外部渠道获取当前时间,用于内部时间系统; 当依附的视频具有快进快退功能时,必须实现这个函数,并返回时间轴上的当前时刻,即已经播放的时间.
- (NSTimeInterval)timeForBarrageRenderer:(BarrageRenderer *)renderer;
@end
/// 弹幕渲染器
@interface BarrageRenderer : NSObject
#pragma mark - life cycle
#pragma mark - control
/// 启动弹幕, 内部时钟从0开始;
/// 若是stop之后的start,则start函数内部会清空records;
/// 视频开始的时候需要同时运行此方法.
- (void)start;
/// 暂停, 已经渲染上去的保持不变, 此时发送弹幕无效, 内部时钟暂停;
/// 视频暂停的时候需要同时运行此方法.
- (void)pause;
/// 停止弹幕渲染, 会清空所有; 再发弹幕就无效了; 一切都会停止;
/// 此方法在不再需要弹幕的时候必须调用,否则可能造成内存泄露.
- (void)stop;
/// 接收弹幕消息, 如果尚未start, 则调用无效.
- (void)receive:(BarrageDescriptor *)descriptor;
#pragma mark - config
/// 画布的边距
@property(nonatomic,assign)UIEdgeInsets canvasMargin;
/// 画布是否拦截事件
@property(nonatomic,assign)BOOL masked;
/// 调整弹幕整体速度, 需要>0, 否则会被抛弃.
@property(nonatomic,assign)CGFloat speed;
/// 如果时光倒流, 弹幕能不能重新显示. 若设置为YES, 则当执行后退8s->5s时,会显示6s时刻上的弹幕.
@property(nonatomic,assign)BOOL redisplay;
/// 获取外部时间的代理,若需将弹幕固定到时间点上,则需设置此代理
@property(nonatomic,weak)id<BarrageRendererDelegate> delegate;
#pragma mark - output
/// 返回给外部的view
@property(nonatomic,weak)UIView * view;
/// 获取当前屏幕弹幕数量,spriteName表示弹幕类名,如果传入nil,则计算屏幕显示出的所有弹幕数量.
- (NSInteger)spritesNumberWithName:(NSString *)spriteName;
/// 逻辑时间,露出参考.
@property(nonatomic,assign,readonly)NSTimeInterval time;
#pragma mark - z-index
/// 是否开启z-index功能,开启之后,性能会稍有降低,绘图会按照z_index进行,值越大,越靠上;默认关闭.
@property(nonatomic,assign)BOOL zIndex;
#pragma mark - record
/// 如需要记录,需要在运行start之后立即运行此函数,内部会通过时间差计算delay;
/// 记录弹幕,可能会序列化到本地; 默认为NO.
@property(nonatomic,assign)BOOL recording;
/// 加载已经存在的弹幕,如果已经start, 会立刻被调用receive; 否则, 会等到start的时候再调用receive.
- (void)load:(NSArray *)descriptors;
/// 弹幕记录数组.
- (NSArray *)records;
@end
工程实现
下面看一下我建立工程的代码。
1. JJBarrageModel.h
#import <Foundation/Foundation.h>
@interface JJBarrageModel : NSObject
@property (nonatomic, copy) NSString *videoTime;
@property (nonatomic, copy) NSString *barrageType;
@property (nonatomic, copy) NSString *fontSize;
@property (nonatomic, copy) NSString *barrageColor;
@property (nonatomic, copy) NSString *timestamp;
@property (nonatomic, copy) NSString *barragePoolId;
@property (nonatomic, copy) NSString *userHash;
@property (nonatomic, copy) NSString *barrageID;
@property (nonatomic, copy) NSString *message;
@property (nonatomic, assign) NSTimeInterval delay;
@end
2. JJBarrageRendererVC.h
#import <UIKit/UIKit.h>
@interface JJBarrageRendererVC : UIViewController
@end
3. JJBarrageRendererVC.m
#import "JJBarrageRendererVC.h"
#import "BarrageRenderer.h"
#import "JJBarrageModel.h"
@interface JJBarrageRendererVC () <BarrageRendererDelegate>
@property (nonatomic, strong) BarrageRenderer *renderer;
@property (nonatomic, assign) NSTimeInterval predictedTime;
@property (nonatomic, strong) NSDate *startDate;
@end
@implementation JJBarrageRendererVC
#pragma mark - Override Base Function
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor darkGrayColor];
[self setupUI];
//初始化弹幕
[self initBarrageRenderer];
}
#pragma mark - Object Private Function
- (void)setupUI
{
UIButton *sendButton = [UIButton buttonWithType:UIButtonTypeCustom];
[sendButton setTitle:@"发送弹幕" forState:UIControlStateNormal];
sendButton.layer.borderColor = [UIColor yellowColor].CGColor;
[sendButton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
sendButton.frame = CGRectMake((self.view.center.x - 50), (self.view.center.y - 10), 100, 20);
[sendButton addTarget:self action:@selector(buttonDidClick) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:sendButton];
}
//弹幕初始化
- (void)initBarrageRenderer
{
self.renderer = [[BarrageRenderer alloc]init];
self.renderer.view.userInteractionEnabled = NO;
self.renderer.masked = NO;
self.renderer.delegate = self;
self.renderer.redisplay = YES;
self.renderer.canvasMargin = UIEdgeInsetsMake(30, 0, 30, 0);
self.predictedTime = 0.0f;
[self start];
[self.view addSubview:self.renderer.view];
}
//开始发送弹幕
- (void)start
{
self.startDate = [NSDate date];
[self.renderer start];
}
//发送弹幕
- (void)sendBarrageWithModel:(JJBarrageModel *)model
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.renderer receive:[self walkImageTextSpriteDescriptorAWithData:model]];
});
}
//加载弹幕描述符
- (BarrageDescriptor *)walkImageTextSpriteDescriptorAWithData:(JJBarrageModel *)model
{
BarrageDescriptor * descriptor = [[BarrageDescriptor alloc] init];
descriptor.spriteName = NSStringFromClass([BarrageWalkTextSprite class]);
descriptor.params[@"direction"] = @(BarrageWalkDirectionR2L);
descriptor.params[@"trackNumber"] = @5;
descriptor.params[@"text"] = model.message?:@"";
descriptor.params[@"textColor"] = [UIColor whiteColor];
descriptor.params[@"shadowColor"] = [UIColor darkGrayColor];
descriptor.params[@"speed"] = @(0.5 * model.message.length + 100);
return descriptor;
}
#pragma mark - Action && Notification
- (void)buttonDidClick
{
JJBarrageModel *model = [[JJBarrageModel alloc] init];
model.message = @"我是个弹幕,弹幕,弹幕啊!";
model.barrageColor = @"ffb412";
model.fontSize = [NSString stringWithFormat:@"%f", 16.0f];
model.delay = 0;
[self sendBarrageWithModel:model];
}
#pragma mark - BarrageRendererDelegate
- (NSTimeInterval)timeForBarrageRenderer:(BarrageRenderer *)renderer
{
NSTimeInterval interval = [[NSDate date]timeIntervalSinceDate:self.startDate];
interval += self.predictedTime;
return interval;
}
@end
功能效果
下面我们就看一下功能效果。
后记
未完,待续~~~