发布于 2016-03-15 20:48:14 | 161 次阅读 | 评论: 0 | 来源: 分享

这里有新鲜出炉的精品教程,程序狗速度看过来!

iOS苹果移动操作系统

苹果iOS是由苹果公司开发的移动操作系统。苹果公司最早于2007年1月9日的Macworld大会上公布这个系统,最初是设计给iPhone使用的,后来陆续套用到iPod touch、iPad以及Apple TV等产品上。


  最近,读完今年的第三本书《大话移动APP测试 Android与iOS》,在读到陈晔前辈改变中国测试行业的决心时,内心无比激动,作为一名初生的开发人员,我可能还无法理解测试行业的本质,但他那份通过分享改变现状的决心我深感共鸣。在此为每一位愿分享愿奉献的朋友点个赞!

  弹幕,国内流行于视频网站A站和B站。网上关于弹幕的实现方法有很多,目前Android平台已经有比较成熟的解决方案DanmakuFlameMaster 。而iOS平台尚无比较成熟的开源库,在借鉴DanmakuFlameMaster的实现思想后,特分享iOS平台弹幕解决方案HJDanmakuDemo。本文将介绍弹幕的大致实现原理。

看过DanmakuFlameMaster源码的朋友都知道,弹幕实现主要需要解决以下几个问题

  1. 弹幕绘制方式
  2. 弹幕时间控制
  3. 弹幕碰撞检测原理
  4. 弹幕暂停及恢复

本文主要从以上4个方面介绍弹幕的详细实现原理。首先是弹幕绘制方式,在DanmakuFlameMaster库中,它主要通过view的自定义draw一帧一帧的绘制来完成弹幕的显示,这种方式最大的问题在于性能以及动画的不流畅。弹幕流畅的前提要求每秒绘制的帧数在30帧以上,而移动设备性能千差万别,当同一时刻需要绘制大量弹幕的时候,对于低端设备就会出现卡帧不流畅的情况,这会大大降低用户的体验。因此,在本项目中放弃采用自定义绘制帧的方式,而是采用系统动画的方式来实现弹幕文本的滚动。


[UIView animateWithDuration:danmaku.remainTime delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    danmaku.label.frame = CGRectMake(-danmaku.size.width, danmaku.py, danmaku.size.width, danmaku.size.height);
} completion:nil];

其次,就是弹幕时间的控制。由于采用系统动画的方式,所以不需要时刻计算每一个弹幕的显示时间以及其X坐标(假设弹幕横向滚动),我们需要做的就是在弹幕需要出现的时候创建它,然后设定弹幕存活的时间,剩余滚动动画交给系统负责,当然,弹幕剩余时间需要我们来更新。本项目中,创建了一个0.5s间隔的定时器,主要负责创建新的弹幕并更新已显示弹幕的剩余时间,也就是说0.5s执行一次计算,如果需要,可以将刷新间隔设置成5s或者更长。


_timer = [NSTimer timerWithTimeInterval:_frameInterval target:self selector:@selector(onTimeCount) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
[_timer fire];

然后,就是弹幕碰撞检测的问题。碰撞检测主要难点在于检测横向滚动弹幕之间的碰撞,弹幕存活时间由其显示时间和存活长短决定,因此,弹幕之间是否碰撞只需检测开始和消失是否碰撞即可。


- (BOOL)checkIsWillHitWithWidth:(float)width DanmakuL:(DanmakuBaseModel *)danmakuL DanmakuR:(DanmakuBaseModel *)danmakuR
{
    if (danmakuL.remainTime<=0) {
        return NO;
    }
    if (danmakuL.px+danmakuL.size.width>danmakuR.px) {
        return YES;
    }
    float minRemainTime = MIN(danmakuL.remainTime, danmakuR.remainTime);
    float px1 = [danmakuL pxWithScreenWidth:width RemainTime:(danmakuL.remainTime-minRemainTime)];
    float px2 = [danmakuR pxWithScreenWidth:width RemainTime:(danmakuR.remainTime-minRemainTime)];
    if (px1+danmakuL.size.width>px2) {
        return YES;
    }
    return NO;
}

最后,弹幕的暂停及恢复。由于弹幕滚动采用系统动画,所以在解决弹幕暂停前需要先了解系统动画的实现原理,有兴趣的朋友可以参考动画解释这篇文章,在此就不做过多介绍。暂停的基本原理就是通过view的presentationLayer获取对象的当前坐标并赋给其frame,然后移除layer动画,考虑到缓冲,可以在当前坐标基础上-1


- (void)pauseRenderer
{
    for (DanmakuBaseModel *danmaku in _drawArray.objectEnumerator) {
        CALayer *layer = danmaku.label.layer;
        CGRect rect = danmaku.label.frame;
        if (layer.presentationLayer) {
            rect = ((CALayer *)layer.presentationLayer).frame;
            rect.origin.x-=1;
        }
        danmaku.label.frame = rect;
        [danmaku.label.layer removeAllAnimations];
    }
}

有兴趣的童鞋可以下载HJDanmakuDemo查看具体使用方法,有什么疑问可以在后面留言。 如果你喜欢,希望能在github上为本demo点上一赞,感谢你的来访!



相关阅读 :
iOS弹幕(源码)实现原理解析
IOS 实现简单的弹幕功能
iOS底层-KVC使用实践以及实现原理
IOS之教你用Xtrace读懂Mantle源码
iOS用三种途径实现一方法有多个返回值
深入浅出-iOS函数式编程的实现 && 响应式编程概念
iOS开发-探索scrollView的实现
IOS单选框RadioButton实现
解析 iOS 动画原理与实现
IOS下实现UI下拉刷新功能
iOS中 Query 的几个方法和如何使用 Wilddog 实现分页加载
iOS开发之ImageView复用实现图片无限轮播
最新网友评论  共有(0)条评论 发布评论 返回顶部

Copyright © 2007-2017 PHPERZ.COM All Rights Reserved   冀ICP备14009818号  版权声明  广告服务