iOS开发中实现显示gif图片的方法
我们知道gif是由一阵阵画面组成的,而且每一帧画面播放的时常可能会不相等,观察上面两个例子,发现他们都没有对gif中每一帧的显示时常做处理,这样的结果就是整个gif中每一帧画面都是以固定的速度向前播放,很显然这并不总会符合需求。
于是自己写一个解析gif的工具类,解决每一帧画面并遵循每一帧所对应的显示时间进行播放。
程序的思路如下:
1、首先使用imageio库中的cgimagesource家在gif文件。
2、通过cgimagesource获取到gif文件中的总的帧数,以及每一帧的显示时间。
3、通过cakeyframeanimation来完成gif动画的播放。
下面直接上我写的解析和播放gif的工具类的代码:
//
// svgifview.h
// svgifsample
//
// created by maple on 3/28/13.
// copyright (c) 2013 smileevday. all rights reserved.
//
#import <uikit/uikit.h>
@interface svgifview : uiview
/*
* @brief desingated initializer
*/
- (id)initwithcenter:(cgpoint)center fileurl:(nsurl*)fileurl;
/*
* @brief start gif animation
*/
- (void)startgif;
/*
* @brief stop gif animation
*/
- (void)stopgif;
/*
* @brief get frames image(cgimageref) in gif
*/
+ (nsarray*)framesingif:(nsurl*)fileurl;
@end
//
// svgifview.m
// svgifsample
//
// created by maple on 3/28/13.
// copyright (c) 2013 smileevday. all rights reserved.
//
#import "svgifview.h"
#import <imageio/imageio.h>
#import <quartzcore/coreanimation.h>
/*
* @brief resolving gif information
*/
void getframeinfo(cfurlref url, nsmutablearray *frames, nsmutablearray *delaytimes, cgfloat *totaltime,cgfloat *gifwidth, cgfloat *gifheight)
{
cgimagesourceref gifsource = cgimagesourcecreatewithurl(url, null);
// get frame count
size_t framecount = cgimagesourcegetcount(gifsource);
for (size_t i = 0; i < framecount; ++i) {
// get each frame
cgimageref frame = cgimagesourcecreateimageatindex(gifsource, i, null);
[frames addobject:(id)frame];
cgimagerelease(frame);
// get gif info with each frame
nsdictionary *dict = (nsdictionary*)cgimagesourcecopypropertiesatindex(gifsource, i, null);
nslog(@"kcgimagepropertygifdictionary %@", [dict valueforkey:(nsstring*)kcgimagepropertygifdictionary]);
// get gif size
if (gifwidth != null && gifheight != null) {
*gifwidth = [[dict valueforkey:(nsstring*)kcgimagepropertypixelwidth] floatvalue];
*gifheight = [[dict valueforkey:(nsstring*)kcgimagepropertypixelheight] floatvalue];
}
// kcgimagepropertygifdictionary中kcgimagepropertygifdelaytime,kcgimagepropertygifunclampeddelaytime值是一样的
nsdictionary *gifdict = [dict valueforkey:(nsstring*)kcgimagepropertygifdictionary];
[delaytimes addobject:[gifdict valueforkey:(nsstring*)kcgimagepropertygifdelaytime]];
if (totaltime) {
*totaltime = *totaltime + [[gifdict valueforkey:(nsstring*)kcgimagepropertygifdelaytime] floatvalue];
}
}
}
@interface svgifview() {
nsmutablearray *_frames;
nsmutablearray *_framedelaytimes;
cgfloat _totaltime; // seconds
cgfloat _width;
cgfloat _height;
}
@end
@implementation svgifview
- (id)initwithcenter:(cgpoint)center fileurl:(nsurl*)fileurl;
{
self = [super initwithframe:cgrectzero];
if (self) {
_frames = [[nsmutablearray alloc] init];
_framedelaytimes = [[nsmutablearray alloc] init];
_width = 0;
_height = 0;
if (fileurl) {
getframeinfo((cfurlref)fileurl, _frames, _framedelaytimes, &_totaltime, &_width, &_height);
}
self.frame = cgrectmake(0, 0, _width, _height);
self.center = center;
}
return self;
}
+ (nsarray*)framesingif:(nsurl *)fileurl
{
nsmutablearray *frames = [nsmutablearray arraywithcapacity:3];
nsmutablearray *delays = [nsmutablearray arraywithcapacity:3];
getframeinfo((cfurlref)fileurl, frames, delays, null, null, null);
return frames;
}
- (void)startgif
{
cakeyframeanimation *animation = [cakeyframeanimation animationwithkeypath:@"contents"];
nsmutablearray *times = [nsmutablearray arraywithcapacity:3];
cgfloat currenttime = 0;
int count = _framedelaytimes.count;
for (int i = 0; i < count; ++i) {
[times addobject:[nsnumber numberwithfloat:(currenttime / _totaltime)]];
currenttime += [[_framedelaytimes objectatindex:i] floatvalue];
}
[animation setkeytimes:times];
nsmutablearray *images = [nsmutablearray arraywithcapacity:3];
for (int i = 0; i < count; ++i) {
[images addobject:[_frames objectatindex:i]];
}
[animation setvalues:images];
[animation settimingfunction:[camediatimingfunction functionwithname:kcamediatimingfunctionlinear]];
animation.duration = _totaltime;
animation.delegate = self;
animation.repeatcount = 5;
[self.layer addanimation:animation forkey:@"gifanimation"];
}
- (void)stopgif
{
[self.layer removeallanimations];
}
// remove contents when animation end
- (void)animationdidstop:(caanimation *)anim finished:(bool)flag
{
self.layer.contents = nil;
}
// only override drawrect: if you perform custom drawing.
// an empty implementation adversely affects performance during animation.
- (void)drawrect:(cgrect)rect
{
// drawing code
}
@end
代码很短也比较容易,就不一一解释了。最开始的那个c函数主要就是用来解析gif的,之所以用c函数是因为我要返回多个信息,而objective-c只能返回一个参数,而且objective-c和c语言可以很方便的混合编程。
另外再介绍两种使用uiimageview的方法:
1. 使用uiwebview播放
// 设定位置和大小
cgrect frame = cgrectmake(50,50,0,0);
frame.size = [uiimage imagenamed:@"guzhang.gif"].size;
// 读取gif图片数据
nsdata *gif = [nsdata datawithcontentsoffile: [[nsbundle mainbundle] pathforresource:@"guzhang" oftype:@"gif"]];
// view生成
uiwebview *webview = [[uiwebview alloc] initwithframe:frame];
webview.userinteractionenabled = no;//用户不可交互
[webview loaddata:gif mimetype:@"image/gif" textencodingname:nil baseurl:nil];
[self.view addsubview:webview];
[webview release];
2.将gif图片分解成多张png图片,使用uiimageview播放。
代码如下:
uiimageview *gifimageview = [[uiimageview alloc] initwithframe:[[uiscreen mainscreen] bounds]];
nsarray *gifarray = [nsarray arraywithobjects:[uiimage imagenamed:@"1"],
[uiimage imagenamed:@"2"],
[uiimage imagenamed:@"3"],
[uiimage imagenamed:@"4"],
[uiimage imagenamed:@"5"],
[uiimage imagenamed:@"6"],
[uiimage imagenamed:@"7"],
[uiimage imagenamed:@"8"],
[uiimage imagenamed:@"9"],
[uiimage imagenamed:@"10"],
[uiimage imagenamed:@"11"],
[uiimage imagenamed:@"12"],
[uiimage imagenamed:@"13"],
[uiimage imagenamed:@"14"],
[uiimage imagenamed:@"15"],
[uiimage imagenamed:@"16"],
[uiimage imagenamed:@"17"],
[uiimage imagenamed:@"18"],
[uiimage imagenamed:@"19"],
[uiimage imagenamed:@"20"],
[uiimage imagenamed:@"21"],
[uiimage imagenamed:@"22"],nil];
gifimageview.animationimages = gifarray; //动画图片数组
gifimageview.animationduration = 5; //执行一次完整动画所需的时长
gifimageview.animationrepeatcount = 1; //动画重复次数
[gifimageview startanimating];
[self.view addsubview:gifimageview];
[gifimageview release];
注意:这个方法,如果gif动画每桢间的时间间隔不同,不能达到此效果。