项目中视频直播有个弹幕功能, 网上也有很多弹幕的 demo, 之前忙于项目进度, 没有细致研究其中是如何实现的. 如今闲暇之余, 就研究一下其中的实现原理.
网上的弹幕 demo, 简单的是用 label 作为一条弹幕, 然后控制 label 的动画, 但是 label 显示样式单一, 做不了图文混排的功能, 所以就有了这篇文章.
最基本的特点:
, 文字越长的弹幕, 跑的越快, 弹幕的速度和文字长度有关系.
, 弹幕不相互碰撞 (开始结束均不碰撞).
, 如果有数据, 会一条接着一跳的播放.
需要考虑的方面:
, 重用或者释放;
, 暂停和继续;
,load 新数据;
, 碰撞问题;
原理分析
检测模型数组里面所有的模型, 是否可以发射 如果可以, 直接发射 dataSource 为数据源
遍历所有的弹道, 在每个弹道里面, 进行检测 (检测开始碰撞 检测结束碰撞)
确定可以发射, 把弹幕视图加到弹道背景里面.
当弹幕移动到屏幕外的时候, 移除弹幕.
技术实现~~
以下是部分核心代码, 完整 https://github.com/AllisonWangJiaoJiao/FDanmakuDemo 参见这里.
- - (BOOL)checkBoomAndBiuWith:(id
- )model {
- CGFloat danmakuH =
- self.frame.size.height / kDandaoCount ;
- // 遍历所有的弹道, 在每个弹道里面, 进行检测 (检测开始碰撞 检测结束碰撞)
- for (
- int i =
- 0 ; i <kDandaoCount; i++) {
- //1. 获取该弹道的绝对等待时间
- NSTimeInterval waitTime = [
- self.laneWaitTimeArr[i] doubleValue];
- if (waitTime>
- 0.0) {
- continue;
- }
- //2. 绝对等待时间没有 暂时可以发射 需要判断 是否与前一个弹幕视图产生碰撞
- UIView * danmakuView = [
- self.delegate danmakuViewWithModel:model];
- NSTimeInterval leftTime = [
- self.laneLeftTimeArr[i] doubleValue];
- // 速度 = (弹幕视图的宽度 + 弹幕背景的宽度)/liveTime
- double speed = ( danmakuView.frame.size.width +
- self.frame.size.width) / model.liveTime;
- double distance = leftTime * speed;
- if (distance>
- self.frame.size.width) {
- continue;
- }
- [
- self.danmakuViewArr addObject:danmakuView];
- // 重置数据
- // 距离 / 秒 = 速度 v
- self.laneWaitTimeArr[i] = @(danmakuView.frame.size.width / speed);
- self.laneLeftTimeArr[i] = @(model.liveTime);
- //3. 弹幕肯定可以发射
- //3.1 先把弹幕视图, 加到弹幕背景里面
- CGRect frame = danmakuView.frame;
- frame.origin =
- CGPointMake(
- self.frame.size.width, danmakuH * i);
- danmakuView.frame = frame;
- [
- self addSubview:danmakuView];
- [
- UIView animateWithDuration:model.liveTime delay:
- 0 options:
- UIViewAnimationOptionCurveLinear animations:^{
- CGRect frame = danmakuView.frame;
- frame.origin.x = - danmakuView.frame.size.width;
- danmakuView.frame = frame;
- } completion:^(
- BOOL finished) {
- [danmakuView removeFromSuperview];
- [
- self.danmakuViewArr removeObject:danmakuView];
- }];
- return
- YES;
- }
- return
- NO;
- }
来源: http://www.tuicool.com/articles/mqe6Fna