FLAnimatedImageView处理gif过程
FLAnimatedImageView处理gif过程
时间控制原理
GIF图片每一帧的delayTime可能都不一样;

在展示下一帧的时间控制机制,不能根据以第一帧为准;

或总动画时长除以帧数来简单做平均值为准,

都是不太好的方案。
FLAnimatedImageView的控制方式,读取每一帧的delayTime算出最大公约数,用CADisplayLink来控制时间的,比如说(如下图),
第二帧到第三帧的控制:第二帧的delayTime=2s,第三帧的delayTime=3s,如果第二帧没到时间,FLAnimatedImageView的image数据保持不变,时间一到就从FLAnimatedImage中获取image,赋值给ImageView。

CADisplayLink处理过程
首先startAnimating中的CADisplayLink初始化,为了防止retain cycle 用了NSProxy weak语义的property,也可以用
__weak typeof(self) wself = self;
...
// block中处理
__strong typeof(wself) sself = wself;
if (!sself) {
return;
}
// 紧跟处理code
反正都与weak有关,都是固定套路了。
CADisplayLink的frameInterval,frameInterval = 1时,refreshRate = 60Hz,frameInterval = 2时,refreshRate = 30Hz;
此处设置的
const NSTimeInterval kDisplayRefreshRate = 60.0; // 60Hz // 最小的frameInterval = 1
self.displayLink.frameInterval = MAX([self frameDelayGreatestCommonDivisor] * kDisplayRefreshRate, );
接下来就是最关键的处理方法- (void)displayDidRefresh:(CADisplayLink *)displayLink;
1,如果self.needsDisplayWhenImageBecomesAvailable==YES,调用[self.layer setNeedsDisplay];,标记layer需要刷新,下一次runloop中displayLayer方法会被调用;然后设置self.needsDisplayWhenImageBecomesAvailable=NO,不到下一帧的时间,不改变ImageView的内容;
赋值代码相当简单:
- (void)displayLayer:(CALayer *)layer
{
// 从 image 方法中取currentFrame作为像是内容
layer.contents = (__bridge id)self.image.CGImage;
}
2,累加时间值accumulator跟当前帧的delayTime比对,注释如下:
/**
* duration属性提供了每帧之间的时间,也就是屏幕每次刷新之间的的时间,一个略小的值;
* frameInterval相当一个>=1的固定值,每次refresh,accumulator都累加一小段时间
**/
self.accumulator += displayLink.duration * displayLink.frameInterval; // While-loop first inspired by & good Karma to: https://github.com/ondalabs/OLImageView/blob/master/OLImageView.m /**
* 1,如果self.accumulator < 当前的delayTime,直接跳过,下一次refresh,accumulator再累加,相当于这一次image的内容不变;
* 2,只有当累加值self.accumulator >= 当前的delayTime(说明已经是累加到这一帧的delayTime的最后,下一帧的开头了),进入while循环,循环内部每次将累加器减掉delayTime(accumulator又回到0状态),以便跳出循环;currentFrameIndex累加,下次refresh时,获取下一帧图像数据;
* 3,如果到达最后一帧,循环次数loopCountdown--,又跳转到首帧图像;
* 4,最主要的一步标记self.needsDisplayWhenImageBecomesAvailable = YES;下一次refresh时,执行[self.layer setNeedsDisplay]; 进行新一帧图像数据的刷新。
**/
while (self.accumulator >= delayTime) {
self.accumulator -= delayTime;
self.currentFrameIndex++;
if (self.currentFrameIndex >= self.animatedImage.frameCount) {
// If we've looped the number of times that this animated image describes, stop looping.
self.loopCountdown--;
if (self.loopCompletionBlock) {
self.loopCompletionBlock(self.loopCountdown);
} if (self.loopCountdown == ) {
[self stopAnimating];
return;
}
self.currentFrameIndex = ;
}
// Calling `-setNeedsDisplay` will just paint the current frame, not the new frame that we may have moved to.
// Instead, set `needsDisplayWhenImageBecomesAvailable` to `YES` -- this will paint the new image once loaded.
self.needsDisplayWhenImageBecomesAvailable = YES;
}
至此就时间控制过程基本处理完成。
另外FLAnimatedImage类,专门根据gif图片大小来限制缓存多少帧,当遇到memoryWarning时,如何重试处理;多次遇到memoryWarning,固定缓存帧数等等功能,而且没有用到dispatch_semaphore等加锁/解锁操作;性能有保证。
FLAnimatedImageView处理gif过程的更多相关文章
- c++ primer plus 第6版 部分二 5- 8章
---恢复内容开始--- c++ primer plus 第6版 部分二 5- 章 第五章 计算机除了存储外 还可以对数据进行分析.合并.重组.抽取.修改.推断.合成.以及其他操作 1.for ...
- 从源码看Azkaban作业流下发过程
上一篇零散地罗列了看源码时记录的一些类的信息,这篇完整介绍一个作业流在Azkaban中的执行过程,希望可以帮助刚刚接手Azkaban相关工作的开发.测试. 一.Azkaban简介 Azkaban作为开 ...
- DBImport V3.7版本发布及软件稳定性(自动退出问题)解决过程分享
DBImport V3.7介绍: 1:先上图,再介绍亮点功能: 主要的升级功能为: 1:增加(Truncate Table)清表再插入功能: 清掉再插,可以保证两个库的数据一致,自己很喜欢这个功能. ...
- HTML渲染过程详解
无意中看到寒冬关于前端的九个问题,细细想来我也只是对第一.二.九问有所了解,正好也趁着这个机会梳理一下自己的知识体系.由于本人对http协议以及dns对url的解析问题并不了解,所以这里之探讨url请 ...
- iOS可视化动态绘制八种排序过程
前面几篇博客都是关于排序的,在之前陆陆续续发布的博客中,我们先后介绍了冒泡排序.选择排序.插入排序.希尔排序.堆排序.归并排序以及快速排序.俗话说的好,做事儿要善始善终,本篇博客就算是对之前那几篇博客 ...
- lua执行字节码的过程介绍
前面一篇文章中介绍了lua给下面代码生成最终的字节码的整个过程,这次我们来看看lua vm执行这些字节码的过程. foo = "bar" local a, b = "a& ...
- centos7+mono4+jexus5.6.2安装过程中的遇到的问题
过程参考: http://www.linuxdot.net/ http://www.jexus.org/ http://www.mono-project.com/docs/getting-starte ...
- 源码分析netty服务器创建过程vs java nio服务器创建
1.Java NIO服务端创建 首先,我们通过一个时序图来看下如何创建一个NIO服务端并启动监听,接收多个客户端的连接,进行消息的异步读写. 示例代码(参考文献[2]): import java.io ...
- zookeeper源码分析之一服务端启动过程
zookeeper简介 zookeeper是为分布式应用提供分布式协作服务的开源软件.它提供了一组简单的原子操作,分布式应用可以基于这些原子操作来实现更高层次的同步服务,配置维护,组管理和命名.zoo ...
随机推荐
- 现有‘abcdefghijkl’12个字符,将其所有的排列按字典序进行排序,给出任意一组排列,说出这租排列在所有排列中是第几小的
题目: 现有‘abcdefghijkl’12个字符,将其所有的排列按字典序进行排序,给出任意一组排列,说出这租排列在所有排列中是第几小的 据说这道题是百度校招的一道算法题,反正我觉得我在学校的时候很可 ...
- IIS环境下部署项目
1.环境部署 1.1安装IIS7 进入控制面板,选择"程序和功能",进入如下页面后,点击"Turn Windows features on or off". 找 ...
- cmapx 保存绘制好的图层
研究了两天,如何保存一绘制好的图层,大致意思都说要使用mapInfo表,然后确定了可定和.TAB表有关.然而网上说的全是垃圾,也不能说全是垃圾,好歹我从中得到了一点点有用的信息,使用mapManage ...
- 八种创建等高列布局【出自w3c】
高度相等列在Web页面设计中永远是一个网页设计师的需求.如果所有列都有相同的背景色,高度相等还是不相等都无关紧要,因为你只要在这些列的父元素中设置一个背景色就可以了.但是,如果一个或多个列需要单独设置 ...
- SQL Server 数据库连接方法
我们用c#写ado或者是asp,都需要连接数据库来读写数据,今天我们就来总结一下数据库连接都有哪些方法. 首先我们就写最直接的方法,在事件中直接连接.(在这里就用WEB页面来展示) 首先我们建立web ...
- innobackup全备与恢复
前提:xtrabackup.mysql安装完成,建立测试库reading.测试表test,并插入三条数据. 1.全备: innobackupex --user=root --password ...
- NancyFx 2.0的开源框架的使用-Basic
这是NancyFx开源框架中的Basic认证,学习一下! 首先当然是新建一个空的Web,BasicDemo 继续在项目中添加Nuget包,记得安装的Nuget包是最新的预发行版 Nancy Nancy ...
- LeetCode5. Longest Palindromic Substring 最长回文子串 4种方法
题目链接:https://leetcode.com/problems/longest-palindromic-substring/ 题意很简单,就是求一个字符串得最长子串,这里的子串指连续的. 本文给 ...
- Hbuilder常用功能汇总
引用 样式表: mui.min.css Js:mui.min.js 常用功能 获取页面 var webView=plus.webview.currentWebview();//获取当前页 var we ...
- [UWP]不怎么实用的Shape指南:自定义Shape
1. 前言 这篇文章介绍了继承并自定义Shape的方法,不过,恐怕,事实上,100个xaml的程序员99个都不会用到.写出来是因为反正都学了,当作写个笔记. 通过这篇文章,你可以学到如下知识点: 自定 ...