前言
随着视频直播类app的崛起,为了增加用户的粘性以及趣味性,弹幕越来越受到视频类应用或者网站的青睐,下面是两种最常见的弹幕效果
![](https://img.haomeiwen.com/i5423128/fa2d62ca06a23b6d.jpg)
![](https://img.haomeiwen.com/i5423128/5404e800dd5ad9e5.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仅供参考,如有需要,请戳这里~
网友评论