实现的效果图
弹幕(barrage),顾名思义是指子弹多而形成的幕布,大量吐槽评论从屏幕飘过时效果看上去像是飞行射击游戏里的弹幕。——来自百度百科
弹幕的特点
1、弹幕可以循环播放
2、弹幕的速度不同
3、弹幕是随机出现的
弹幕的肢解分析
弹幕的自动追加的重要的三个节点
1、创建弹幕view开始的时间
2、弹幕view完全进入屏幕
3、弹幕view完全飞出屏幕
初始化弹幕,随机分配弹幕轨迹
// 弹道数组
NSMutableArray *trajectorys = [NSMutableArray arrayWithArray:@[@(0),@(1),@(2),@(3)]];
for (int i = 0; i < 4; i++) { // < trajectorys.count
if (self.bulletComments.count > 0) {
// 通过随机数获取弹幕的轨迹
NSInteger index = arc4random()%trajectorys.count;
int trajectory = [[trajectorys objectAtIndex:index] intValue];
[trajectorys removeObjectAtIndex:index];
// 从弹幕数组中逐一取出弹幕数据
NSString *comment = [self.bulletComments firstObject];
[self.bulletComments removeObjectAtIndex:0];
// 创建弹幕view
[self createBulletView:comment trajectory:trajectory];
}
}
根据弹幕内容和弹幕轨迹创建弹幕
// 初始化XZBulletView
XZBulletView *view = [[XZBulletView alloc] initWithComment:comment];
view.trajectory = trajectory;
[self.bulletViews addObject:view];
__weak typeof(view) weakView = view;
__weak typeof(self) weakSelf = self;
view.moveStatusBlock = ^(MoveStatus status){
if (self.bStopAnimation) { // 如果停止动画,直接return
return;
}
switch (status) {
case Start:
{
// 弹幕开始进入屏幕,将view加入到弹幕管理的变量中bulletViews
[weakSelf.bulletViews addObject:weakView];
break;
}
case Enter:
{
// 弹幕完全进入屏幕,判断是否还有其他内容,如果有则在该弹幕轨迹中创建一个弹幕
NSString *commentNext = [weakSelf nextComment];
if (commentNext) { // 创建新的弹幕
[weakSelf createBulletView:commentNext trajectory:trajectory];
}
break;
}
case End:
{
// 弹幕完全飞出屏幕后,从bulletViews中删除,释放资源
if ([weakSelf.bulletViews containsObject:weakView]) {
[weakView stopAnimation];
[weakSelf.bulletViews removeObject:weakView];
}
// 循环
if (weakSelf.bulletViews.count == 0) {
// 说明屏幕上已经没有弹幕,开始循环滚动
weakSelf.bStopAnimation = YES;
[weakSelf start];
}
break;
}
default:
break;
}
// // 移出屏幕后销毁弹幕并释放资源
// [weakView stopAnimation];
// [weakSelf.bulletViews removeObject:weakView];
};
// 回调到controller
if (self.generateViewBlock) {
self.generateViewBlock(view);
}
开始弹幕,并在动画完成后,释放掉自己
// 根据弹幕长度执行动画效果
// 根据 v = s/t,时间相同情况下,距离越长,速度就越快;
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat duration = 4.0f;
CGFloat wholeWidth = screenWidth + CGRectGetWidth(self.bounds);
// 弹幕开始
if (self.moveStatusBlock) {
self.moveStatusBlock(Start);
}
// t = s / v;
CGFloat speed = wholeWidth / duration;
CGFloat enterDurartion = CGRectGetWidth(self.bounds) / speed;
// 弹幕的自动追加
[self performSelector:@selector(enterScreen) withObject:nil afterDelay:enterDurartion + 2];
// 因为要改变frame的值,所以要加__block
__block CGRect frame = self.frame;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
// 改变x坐标
frame.origin.x -= wholeWidth;
self.frame = frame;
} completion:^(BOOL finished) {
// 动画完成后,释放掉自己
[self removeFromSuperview];
// 回调:知道什么时候释放
if (self.moveStatusBlock) {
self.moveStatusBlock(End);
}
}];
下面附上实现的demo