<span style="font-family: Arial, Helvetica, sans-serif;"> </span><span style="font-family: Arial, Helvetica, sans-serif; "><strong><span style="font-size:18px;">本文主要解析GIF图片的每一帧,然后用定时器循环播放实现GIF动画。</span></strong></span>
源于这篇GIF动画的深思,还是一些需求产生的:如,我只想看GIF动画播放一次(2,3,4...),然后做其他事;或者动画每帧间隔太慢了,想调整怎么办?等等。。。,作为程序员,大家想要的感觉就是,一切尽在我的掌控之中,我想要停就马上停止,想要动就立刻动起来。不好的情况是,我没法控制它,我想要干另外一件事了,它还不能停止。
在iOS平台,大家所熟知的有三种播放方式:
1、用UIWebView 实现:也是比较简单的方式,这种方式主要就是把GIF图片构造入一个html中,然后让UIWebView去解析这个html,然后播放动画。
这种方式的缺点:使用者无法知道这个动画循环一次完成,反正是uiwebview解析,我只看到动画,其他的无法控制。
2、UIImageView自身支持的动画:简单的把GIF每一帧图片解析出来,然后生成UIImage数组,
self.imageView.animationImages = imagesArray;
self.imageView.animationDuration = imageDuration;
[self.imageView startAnimating];
然后就可以动画就开始了,或者使用CAKeyframeAnimation 也可以。这几个都一样的是我们都要解析GIF内的每一帧图片,然后组成一个图片数组来播放动画。
缺点:GIF由很多帧图片组成,然后播放时有个播放帧时间间隔,每一帧的间隔是不一样的。若是上面这种方式的动画播放,它就会设置一个平均每帧时间,这样播放出来的动画也许就不是原来的效果了。
更严重的是GIF图片稍大一点内存就暴涨,一个600KB的GIF解析出来后由50张UIImage,这时候内存会涨到70MB,及时这个应用什么也不干;刚开始我发现好像也能接受,但我们有一个5MB的GIF,解析后有200多张UIImage,这时候内存一下涨到200MB,马上应用就crash了。
3、利用CADisplayLink或NSTimer循环播放:也就是我更推荐的一种
存储图片信息采用 CGImageSourceRef:
<span style="font-size:18px;"> <span style="white-space:pre"> </span>_gifSourceRef = CGImageSourceCreateWithURL((__bridge CFURLRef)[NSURL fileURLWithPath:gifPath], NULL);
<span style="white-space:pre"> </span> self.frameCount = CGImageSourceGetCount(_gifSourceRef);</span>
</pre><pre name="code" class="objc">
然后在定时器中不断更新图片,根据每一帧的间隔来更换,就可以达到效果:
<span style="font-size:18px;"> <span style="white-space:pre"> </span>CGImageRef ref = CGImageSourceCreateImageAtIndex(_gifSourceRef, self.currentFrameIndex, NULL);
self.layer.contents = (__bridge id)(ref);
CGImageRelease(ref);</span>
解析每一帧的时间可以用下面的方法:
<span style="font-size:18px;">- (float)frameDurationAtIndex:(size_t)index
{
CFDictionaryRef dictRef = CGImageSourceCopyPropertiesAtIndex(_gifSourceRef, index, NULL);
NSDictionary *dict = (__bridge NSDictionary *)dictRef;
NSDictionary *gifDict = (dict[(NSString *)kCGImagePropertyGIFDictionary]);
NSNumber *unclampedDelayTime = gifDict[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
NSNumber *delayTime = gifDict[(NSString *)kCGImagePropertyGIFDelayTime];
CFRelease(dictRef);
if (unclampedDelayTime.floatValue) {
return unclampedDelayTime.floatValue;
}else if (delayTime.floatValue) {
return delayTime.floatValue;
}else{
return 1/30.f;
}
}</span>
这样我们就可以在定时器响应函数里做处理来更换图片,实现动画。
若想看详细实现源码,请看GitHubDemo,主要实现第三种播放方式,因为在内存方面,保持原动画效果更好的方式(每一帧的间隔)。