笔记-iOS弹幕(源码)实现原理解析
最近,读完今年的第三本书《大话移动APP测试 Android与iOS》,在读到陈晔前辈改变中国测试行业的决心时,内心无比激动,作为一名初生的开发人员,我可能还无法理解测试行业的本质,但他那份通过分享改变现状的决心我深感共鸣。在此为每一位愿分享愿奉献的朋友点个赞!
弹幕,国内流行于视频网站A站和B站。网上关于弹幕的实现方法有很多,目前Android平台已经有比较成熟的解决方案DanmakuFlameMaster 。而iOS平台尚无比较成熟的开源库,在借鉴DanmakuFlameMaster的实现思想后,特分享iOS平台弹幕解决方案HJDanmakuDemo。本文将介绍弹幕的大致实现原理。
看过DanmakuFlameMaster源码的朋友都知道,弹幕实现主要需要解决以下几个问题
- 弹幕绘制方式
- 弹幕时间控制
- 弹幕碰撞检测原理
- 弹幕暂停及恢复
本文主要从以上4个方面介绍弹幕的详细实现原理。首先是弹幕绘制方式,在DanmakuFlameMaster库中,它主要通过view的自定义draw一帧一帧的绘制来完成弹幕的显示,这种方式最大的问题在于性能以及动画的不流畅。弹幕流畅的前提要求每秒绘制的帧数在30帧以上,而移动设备性能千差万别,当同一时刻需要绘制大量弹幕的时候,对于低端设备就会出现卡帧不流畅的情况,这会大大降低用户的体验。因此,在本项目中放弃采用自定义绘制帧的方式,而是采用系统动画的方式来实现弹幕文本的滚动。
Objective-C
[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或者更长。
Objective-C
_timer = [NSTimer timerWithTimeInterval:_frameInterval target:self selector:@selector(onTimeCount) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
[_timer fire];
然后,就是弹幕碰撞检测的问题。碰撞检测主要难点在于检测横向滚动弹幕之间的碰撞,弹幕存活时间由其显示时间和存活长短决定,因此,弹幕之间是否碰撞只需检测开始和消失是否碰撞即可。
Objective-C
- (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) {
最后,弹幕的暂停及恢复。由于弹幕滚动采用系统动画,所以在解决弹幕暂停前需要先了解系统动画的实现原理,有兴趣的朋友可以参考动画解释这篇文章,在此就不做过多介绍。暂停的基本原理就是通过view的presentationLayer获取对象的当前坐标并赋给其frame,然后移除layer动画,考虑到缓冲,可以在当前坐标基础上-1
Objective-C
- (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弹幕(源码)实现原理解析的更多相关文章
- Spring笔记(3) - debug源码AOP原理解析
案例 @EnableAspectJAutoProxy//开启基于注解的aop模式 @Configuration public class AOPConfig { //业务逻辑类加入容器中 @Bean ...
- 笔记-twisted源码-import reactor解析
笔记-twisted源码-import reactor解析 1. twisted源码解析-1 twisted reactor实现原理: 第一步: from twisted.internet ...
- Laravel学习笔记之Session源码解析(上)
说明:本文主要通过学习Laravel的session源码学习Laravel是如何设计session的,将自己的学习心得分享出来,希望对别人有所帮助.Laravel在web middleware中定义了 ...
- memcached学习笔记——存储命令源码分析上篇
原创文章,转载请标明,谢谢. 上一篇分析过memcached的连接模型,了解memcached是如何高效处理客户端连接,这一篇分析memcached源码中的process_update_command ...
- memcached学习笔记——存储命令源码分析下篇
上一篇回顾:<memcached学习笔记——存储命令源码分析上篇>通过分析memcached的存储命令源码的过程,了解了memcached如何解析文本命令和mencached的内存管理机制 ...
- MyBatis 源码分析 - 配置文件解析过程
* 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...
- jQuery源码:从原理到实战
jQuery源码:从原理到实战 jQuery选择器对象 $(".my-class"); document.querySelectorAll*".my-class" ...
- ios源码-ios游戏源码-ios源码下载
游戏源码 一款休闲类的音乐小游戏源码 该源码实现了一款休闲类的音乐小游戏源码,该游戏的源码很简单,而且游戏的玩法也很容易学会,只要我们点击视图中的grid,就可以 人气:2943运行环境:/Xco ...
- [转]【安卓笔记】AsyncTask源码剖析
[转][安卓笔记]AsyncTask源码剖析 http://blog.csdn.net/chdjj/article/details/39122547 前言: 初学AsyncTask时,就想研究下它的实 ...
随机推荐
- xcode 开发ios兼容性问题的上下黑边 和 coco2d-x 游戏分辨率适配 ResolutionPolicy::FIXED_WIDTH 都会引起上下黑边问题!!!
1:Xcode6在iPhone5+iOS7模拟器上编译,上下有黑边问题 问题描述: Xcode6环境下,对iPhone5或iPhone5s模拟器,在iOS7或iOS7.1下运行,屏幕上下有黑边.在iO ...
- CURL与PHP-CLI的应用【CLI篇】
CLI的普通应用 什么是PHP-CLI php-cli是php Command Line Interface的简称,即PHP命令行接口,在windows和linux下都是支持PHP-CLI模式的; 为 ...
- Linux 阿里云挂载新分区
阿里云服务器可以自己购买数据盘并挂载使用,虽然官方也提供了挂载的教程,但是还是有些朋友不清楚其中的细节,为此,我在这里来给大家分享一下详细的挂载办法. 工具/原料 已经购买开通阿里云服务器,并且在开通 ...
- IDirect3DDevice9::GetRenderTargetData
翻译自DXSDK 将渲染目标数据从设备内存拷贝到系统内存. HRESULT GetRenderTargetData( [in] IDirect3DSurface9 *pRenderTarget, ...
- python学习笔记五--文件
任何情况下文本文件在Python里均是字符串模式. 一.创建一个文件,并写入: 函数open(文件名,w) 二.打开一个文件,并读取: 函数open(文件名,r),“r”是默认值,可以不用写 三.使用 ...
- String Split 和 Join
很多时候处理字符串数据,比如从文件中读取或者存入 - 我们可能需要加入分隔符(如CSV文件中的逗号),或使用一个分隔符来合并字符串序列. 很多人都知道使用split()的方法,但使用与其对应的Join ...
- git rev-list
git-rev-list - Lists commit objects in reverse chronological order 按照时间顺序倒序排列的commit Update: If all ...
- Android-xUtils框架介绍(二)
昨天对xUtils整体上做了一个简单的介绍,今天咱们就代码码起,真刀实枪的也看看,看看如何快速便捷的把xUtils给集成到大家的项目中去.xUtils中有四大组件可以供我们使用,分别是ViewUtil ...
- maven常用插件配置详解
常用插件配置详解Java代码 <!-- 全局属性配置 --> <properties> <project.build.name>tools</proje ...
- 变量赋值(引用) php内核的实现(二)
<?php $a=1; $b=&$a; $c=2; $a=&$c; echo $a."\n"; echo $b; 2 1 结论: 首先保存 左值的内存地址, ...