虚位以待(AD)
虚位以待(AD)
首页 > 软件编程 > IOS编程/Objective-C > 浅谈iOS如何做弹幕

浅谈iOS如何做弹幕
类别:IOS编程/Objective-C   作者:码皇   来源:wzy89的博客     点击:

iOS弹幕demo网上有很多,而且大多数是开源的,很多源代码我们可以自己查看。弹幕有哪些特点呢?

iOS弹幕demo网上有很多,而且大多数是开源的,很多源代码我们可以自己查看。

弹幕有哪些特点呢?

最基本的特点:

1、文字越长的弹幕,跑的越快,弹幕的速度和文字长度有关系。

2、弹幕不相互碰撞。

3、如果有数据,会一条接着一跳的播放。

基于以上的基本特点,我们可以很简单的想到iOS中可以实现的方式:

1、在view中一贞一贞的draw

2、用系统的动画去做

上面一种柔性很强,可是对编程功底要求比较高,搞不好又影响了性能,还做不出好的效果。

下面一种很简单,只需要动画做好分段,处理好动画间的衔接就可以了;可是柔性相对较差一点。

这里采用系统动画来做,这样我们只需要做好下面几个方面就OK了:

1、重用或者释放;

2、暂停和继续;

3、load新数据;

4、碰撞问题;

这里简单的贴一下思路,希望能为各位敞开一扇门。

首先我们做一个单独的带动画的视图,作为我们的弹幕基本试图,后面我们只需要把这些试图组合起来就成为我们想要的弹幕了。

 

    @interface BulletView : UIView@property (nonatomic, copy) void(^moveBlock)(CommentMoveStatus status);
    //状态回调的block@property (nonatomic, assign) NSInteger trajectory;
    //所在轨道编号- (instancetype)initWithCommentDic:(BulletSettingDic *)commentDic;
    //这里的BulletSettingDic是一个自定义的类,里面主要设置了我们弹幕的背景颜色、文字颜色、字体、速率等- (void)reloadDataWithDic:(BulletSettingDic *)reloadDic;
    //写这个方法方便重用- (void)startAnimation;
    - (void)stopAnimation;
    - (void)pauseAnimation;
    - (void)resumeAnimation;
    @end

 

CommentMoveStatus是一个枚举集合,里面设置了动画的几种状态:

 

    typedef NS_ENUM(NSInteger, CommentMoveStatus){
    MoveIn, Enter, MoveOut}
    ;

BulletSettingDic是一个设置类,里面给出了弹幕视图的各种设置参数,头文件如下:

 

这个里面的内容,我们可以随便自定义,然后修改写入视图就好了。

 

    @interface BulletSettingDic : NSObject{
    NSMutableDictionary *_settingDic;
    }
    //设置字颜色-(void)setBulletTextColor:(UIColor *)color;
    -(UIColor *)bulletTextColor;
    //设置背景颜色-(void)setBulletBackgroundColor:(UIColor *)color;
    -(UIColor *)bulletBackgroundColor;
    //设置字体-(void)setBulletTextFont:(UIFont *)font;
    -(UIFont *)bulletTextFont;
    //设置内容-(void)setbulletText:(NSString *)text;
    -(NSString *)bulletText;
    //设置高度-(void)setBulletHeight:(CGFloat)height;
    -(CGFloat)bulletHeight;
    //设置动画时长-(void)setBulletAnimationDuration:(float)duration;
    -(float)bulletAnimationDuration;
    //设置速度比率-(void)setBulletAnimationSpeedRate:(float)speedRate;
    -(float)bulletAnimationSpeedRate;
    -(NSMutableDictionary *)settingDic;
    @end

 

下面是核心思路:

 

    //开始动画- (void)startAnimation{
    __block CGRect frame = self.frame;
    __unsafe_unretained typeof(self)weakSelf = self;
    //计算移动的时间 CGFloat dur = (CGRectGetMinX(frame)-_screenWidth)/_real_speed;
    [UIView animateWithDuration:dur delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    frame.origin.x = _screenWidth;
    weakSelf.frame = frame;
    }
    completion:^(BOOL finished) {
    [weakSelf.layer removeAllAnimations];
    //弹幕开始进入屏幕 if (weakSelf.moveBlock) weakSelf.moveBlock(MoveIn);
    [weakSelf beginMoveIn];
    }
    ];
    }
    //开始移入-->完全进入-(void)beginMoveIn{
    __block CGRect frame = self.frame;
    __unsafe_unretained typeof(self)weakSelf = self;
    //计算移动的时间 CGFloat dur = CGRectGetWidth(frame)/_real_speed;
    [UIView animateWithDuration:dur delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    frame.origin.x = _screenWidth-CGRectGetWidth(frame);
    weakSelf.frame = frame;
    }
    completion:^(BOOL finished) {
    [weakSelf.layer removeAllAnimations];
    //弹幕完全进入屏幕 if (weakSelf.moveBlock) weakSelf.moveBlock(Enter);
    [weakSelf enterIn];
    }
    ];
    }
    //完全进入-->完全移出-(void)enterIn{
    __block CGRect frame = self.frame;
    __unsafe_unretained typeof(self)weakSelf = self;
    CGFloat dur = _screenWidth/_real_speed;
    [UIView animateWithDuration:dur delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    frame.origin.x = -CGRectGetWidth(frame);
    weakSelf.frame = frame;
    }
    completion:^(BOOL finished) {
    //弹幕完全离开屏幕 if (weakSelf.moveBlock) weakSelf.moveBlock(MoveOut);
    [weakSelf.layer removeAllAnimations];
    [weakSelf removeFromSuperview];
    }
    ];
    }
这里面,我做了三段动画:开始-->移入,移入-->完全移入,完全移入-->完全移出,然后每一个完成后都会有相应的block回调出去(这样做是为了方便我们根据状态进行数据和视图的处理,下面会用到)。

 

_real_speed是动画移动的实际速度,它是由动画移动的速度率和速度相乘得到的,动画的速度是通过屏幕宽度和文本宽度以及动画时间计算得到的,速度率是设置的。

关于暂停和继续,我使用CALayer里面与CAMediaTimming相关的方法,改变速度,纪录时间,做到的。代码如下:

 

    //暂停动画- (void)pauseAnimation{
    CALayer *layer = self.layer;
    layer.fillMode = kCAFillModeForwards;
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
    layer.speed = 0.0;
    layer.timeOffset = pausedTime;
    }
    //继续动画- (void)resumeAnimation{
    CALayer*layer = self.layer;
    CFTimeInterval pausedTime = [layer timeOffset];
    layer.speed = 1.0;
    layer.timeOffset = 0.0;
    layer.beginTime = 0.0;
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
    layer.beginTime = timeSincePause;
    }
停止和开始就不详述了。

 

下面说视图的重用,我用了两个数组来做视图的重用,当有弹幕视图移出屏幕的时候我会把移出的视图保存在一个数组中。

在下一个视图制作的时候,直接设置取出来重新加载数据,而不是重新创建对象。

核心操作很简单:

 

    if (_reuseableBulletArray.count) {
    view = [_reuseableBulletArray firstObject];
    [view reloadDataWithDic:_bulletDic];
    [_reuseableBulletArray removeObjectAtIndex:0];
    }
    else {
    view = [[BulletView alloc] initWithCommentDic:_bulletDic];
    }
    [_bulletArray addObject:view];

 

 

然后在合适的地方(一般是有弹幕视图移出屏幕的地方):

 

    [_bulletArray removeObject:weakBulletView];
    [_reuseableBulletArray addObject:weakBulletView];

这样就可以不用创建很多的对象了。

 

相关热词搜索:
上一篇:iOS - 百度推送
下一篇:iOS 开发如何入门