欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS开发中实现显示gif图片的方法

程序员文章站 2022-04-12 11:05:29
我们知道gif是由一阵阵画面组成的,而且每一帧画面播放的时常可能会不相等,观察上面两个例子,发现他们都没有对gif中每一帧的显示时常做处理,这样的结果就是整个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动画每桢间的时间间隔不同,不能达到此效果。