LGJBarrageModel.h
#import <Foundation/Foundation.h>
@interface LGJBarrageModel : NSObject
@property(nonatomic,copy)NSString *userName;
@property(nonatomic,copy)NSString *userMessage;
@property(nonatomic,copy)NSString *userPicUrl;
@end
BarrageView.h
#import <UIKit/UIKit.h>
@class LGJBarrageModel;
@interface BarrageView : UIView
//记录最后一个弹幕的View 通过这个View来计算是显示在哪个弹幕轨道上
@property(nonatomic,copy)UIView *lastAnimationView;
//发送弹幕
-(void)barrageSendMsg:(LGJBarrageModel *)msgModel;
@end
BarrageView.m
#import "BarrageView.h"
#import "LGJBarrageModel.h"
#define K_SCREEN_BOUNS [UIScreen mainScreen].bounds
#define K_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define K_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
@interface BarrageView()
{
CGFloat _minSpaceTime;//最小间距时间
}
@property(nonatomic, strong)NSMutableArray *dataArr;//数据源
@property(nonatomic, strong)NSMutableArray *reuseArr;//弹幕重用
@end
@implementation BarrageView
-(instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor cyanColor];
[self initConfig];
}
return self;
}
-(void)initConfig{
self.dataArr = [NSMutableArray array];
self.reuseArr = [NSMutableArray array];
UIView *view = [self createView];
[self.reuseArr addObject:view];
_minSpaceTime = 1;
[self checkStartAnimatiom];
}
//创建UI子视图
-(UIView *)createView{
UIView *bgView = [[UIView alloc]initWithFrame:CGRectMake(K_SCREEN_WIDTH, 0, 0, CGRectGetHeight(self.frame))];
bgView.backgroundColor = [UIColor colorWithWhite:0 alpha:.3];
UIImageView *headerImageView = [[UIImageView alloc]initWithFrame:CGRectMake(2, 2, CGRectGetHeight(self.frame) - 4, CGRectGetHeight(self.frame)-4)];
headerImageView.layer.cornerRadius = headerImageView.frame.size.width / 2;
headerImageView.layer.masksToBounds = YES;
headerImageView.tag = 1000;
headerImageView.backgroundColor = [UIColor redColor];
[bgView addSubview:headerImageView];
UILabel *label= [[UILabel alloc]initWithFrame:CGRectMake(CGRectGetMaxX(headerImageView.frame) + 2, 0, 0, 14)];
label.font = [UIFont systemFontOfSize:14];
label.tag = 1001;
[bgView addSubview:label];
UILabel *msgLabel = [[UILabel alloc]initWithFrame:CGRectMake(CGRectGetMaxX(headerImageView.frame) + 2, CGRectGetMaxY(label.frame), 0, 14)];
msgLabel.font = [UIFont systemFontOfSize:14];
msgLabel.tag = 1002;
[bgView addSubview:msgLabel];
[self addSubview:bgView];
return bgView;
}
-(void)checkStartAnimatiom{
if (self.dataArr.count > 0) {
if (self.reuseArr.count > 0) { //当重用池当中有备用弹幕UI时候
UIView *view = [self.reuseArr firstObject];
[self.reuseArr removeObject:view];
[self startAnimationWithView:view];
}else{
UIView *view = [self createView];
[self startAnimationWithView:view];
}
}
__weak typeof(self)weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_minSpaceTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__strong typeof(self)strongSelf = weakSelf;
[strongSelf checkStartAnimatiom];
});
}
-(void)startAnimationWithView:(UIView *)view{
LGJBarrageModel *model = [self.dataArr firstObject];
//计算昵称的长度
CGSize size =[model.userName boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 14) options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14]} context:nil].size;
//计算消息的长度
CGSize msgSize =[model.userMessage boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 14) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:14]} context:nil].size;
UIImageView *headerImageView;//头像
UILabel *userNameLabel;//昵称
UILabel *msgLabel;//消息内容
for (UIView *subView in view.subviews) {
if (subView.tag == 1000) {
headerImageView = (UIImageView *) subView;
headerImageView.image = [UIImage imageNamed:model.userPicUrl];
}else if (subView.tag == 1001){
userNameLabel = (UILabel *)subView;
userNameLabel.text = model.userName;
CGRect rect = userNameLabel.frame;
rect.size.width = size.width;
userNameLabel.frame = rect;
}else{
msgLabel = (UILabel *)subView;
msgLabel.text = model.userMessage;
CGRect rect = msgLabel.frame;
rect.size.width = msgSize.width;
msgLabel.frame = rect;
}
}
//重新设置弹幕的总体宽度 = 头像宽度 + 头像左右两侧距离 + (如果名字宽度大于消息内容宽度,以名字宽度为基准,如果名字宽度小于消息内容宽度,以消息内容宽度为基准)
view.frame = CGRectMake(K_SCREEN_WIDTH, 0, CGRectGetWidth(headerImageView.frame) + 4 + ((CGRectGetWidth(userNameLabel.frame) > CGRectGetWidth(msgLabel.frame))?CGRectGetWidth(userNameLabel.frame):CGRectGetWidth(msgLabel.frame)), CGRectGetHeight(self.frame));
//不管弹幕长短 速度要求一致 V速度为固定值 100 可以根据实际需要自行调整
//S长度 = 屏幕的宽度加上弹幕的宽度
//V速度 = S长度/t时间 t(时间) = S(路程)/ V (速度)
CGFloat duration = (view.frame.size.width + K_SCREEN_WIDTH ) / 100;
//最小间距运行时间为:弹幕从屏幕外完全移入屏幕内的时间 + 间距的时间
_minSpaceTime = (view.frame.size.width + 30) / 100;
_lastAnimationView = view;//最后做动画的view
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
//运行至左侧屏幕外
CGRect rect = view.frame;
view.frame = CGRectMake(-rect.size.width, 0, rect.size.width, rect.size.height);
} completion:^(BOOL finished) {
view.frame = CGRectMake(K_SCREEN_WIDTH, 0, 0, CGRectGetHeight(self.frame));
//重新加入重用池
[self.reuseArr addObject:view];
}];
//将这个弹幕数据移除
[self.dataArr removeObject:model];
}
-(void)barrageSendMsg:(LGJBarrageModel *)msgModel{
[self.dataArr addObject:msgModel];
}
ViewController.m中的使用
#import "ViewController.h"
#import "BarrageView.h"
#import "LGJBarrageModel.h"
#define K_SCREEN_BOUNS [UIScreen mainScreen].bounds
#define K_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
#define K_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
@interface ViewController ()
@property(nonatomic,strong)BarrageView *barrageViewOne;
@property(nonatomic,strong)BarrageView *barrageViewTwo;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self createSubView];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)createSubView{
_barrageViewOne = [[BarrageView alloc]initWithFrame:CGRectMake(0, 200, K_SCREEN_WIDTH, 34)];
[self.view addSubview:_barrageViewOne];
_barrageViewTwo = [[BarrageView alloc]initWithFrame:CGRectMake(0, 300, K_SCREEN_WIDTH, 34)];
[self.view addSubview:_barrageViewTwo];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(sendMesaage) userInfo:nil repeats:YES];
[timer fire];
}
-(void)sendMesaage{
LGJBarrageModel *model = [[LGJBarrageModel alloc]init];
model.userName = @[@"周伦",@"周润发",@"刘德华g",@"梁朝伟ddd",@"王祖贤ddddd",@"陈ddddddd冠希",@"张柏芝",@"谢霆dd锋",@"张d雨",@"见",@"刘斌",@"梁森ddddd",@"宏dd杰",@"d范玉",@"郑亚卓"][rand()%15];
model.userMessage = @[@"哈哈",@"嘿嘿",@"v不能给你",@"好的红红火火",@"点点滴滴",@"迭代反反复复",@"反反复复",@"哥哥哥哥哥哥哥哥哥哥",@"点点滴滴淡淡的复古哈哈",@"的点点滴滴",@"发个广告广告",@"生生世世的方法",@"的地方改革",@"的电饭锅哼哼唧唧",@"法规和斤斤计较"][rand()%15];
model.userPicUrl = @[@"1",@"2",@"3"][rand()%3];
NSLog(@"userName=%@",model.userName);
NSLog(@"userMessage=%@",model.userMessage);
CGFloat onePosition = _barrageViewOne.lastAnimationView.layer.presentationLayer.frame.size.width + _barrageViewOne.lastAnimationView.layer.presentationLayer.frame.origin.x;
CGFloat twoPosition = _barrageViewTwo.lastAnimationView.layer.presentationLayer.frame.size.width + _barrageViewTwo.lastAnimationView.layer.presentationLayer.frame.origin.x;
if (onePosition < twoPosition) {
[_barrageViewOne barrageSendMsg:model];
}else{
[_barrageViewTwo barrageSendMsg:model];
}
}