iOS 4种方法显示GIF

GIF作为一种淘汰的图像类型文件,和flash一样,直至现在依然存在于我们生活中的每一个角落。

有时候在iOS中使用GIF会比使用帧动画来的更加方便。

iOS中加载GIF的方法大致分为以下几类:

(1)使用UIWebView播放GIF数据流。弊端是GIF图片只能播放一次(网上的很多博客都说可以播放,不知道是不是iOS版本的问题,还是这可以播放指的就是1次)

(2)将GIF制作成一个本地网页,用UIVebView显示这个网页。弊端是GIF同样只能播放一次。

(2)预先将GIF中的图片提取出来,然后UIImageView每隔一定间隔显示一张图片。

(3)在运行时,通过代码提取GIF中的每一帧和间隔时间,通过帧动画CAKeyframeAnimation来播放。(该方法有点问题,每一帧的信息都能获取的到,但是动画无法播放,因此我还在调试,敬请期待)。


下面是实现以上技术的关键代码:

1、ViewController.m

//
//  ViewController.m
//  GifDemo
//
//  Created by 555chy on 6/17/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import "ViewController.h"
//#import <MobileCoreServices/MobileCoreServices.h>
#import "GifView.h"


#define IMAGE_NAME  @"resource/20140830549"
#define IMAGE_TYPE  @"gif"

@interface ViewController () {
    CGRect contentRect;
}

@end

@implementation ViewController

CGRect screenRect;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    self.navigationItem.title = @"chy龙神";
    [self getContentRect];
    
    /*
    extern const CFStringRef kUTTypeJPEG                                 __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
    extern const CFStringRef kUTTypeJPEG2000                             __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
    extern const CFStringRef kUTTypeTIFF                                 __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
    extern const CFStringRef kUTTypePICT                                 __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
    extern const CFStringRef kUTTypeGIF                                  __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
    extern const CFStringRef kUTTypePNG                                  __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
    extern const CFStringRef kUTTypeQuickTimeImage                       __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
    extern const CFStringRef kUTTypeAppleICNS                            __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
    extern const CFStringRef kUTTypeBMP                                  __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
    extern const CFStringRef kUTTypeICO                                  __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_3_0);
    extern const CFStringRef kUTTypeRawImage                             __OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0);
    extern const CFStringRef kUTTypeScalableVectorGraphics               __OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0);
    extern const CFStringRef kUTTypeLivePhoto                            __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_9_1);
     */
    
    [self loadGifInWebView1];
    [self loadGifInWebView2];
    [self loadGifInImageView];
    [self loadGifInGifView];
}

-(void)getContentRect {
    screenRect = [UIScreen mainScreen].bounds;
    contentRect = self.navigationController.navigationBar.frame;
    NSLog(@"navigationRect = (%f,%f) %f*%f", contentRect.origin.x, contentRect.origin.y, contentRect.size.width, contentRect.size.height);
    contentRect.origin.y = contentRect.size.height;
    contentRect.size.height = screenRect.size.height - contentRect.size.height;
}

//使用webview加载gif只能不放一轮,不能循环播放
-(void)loadGifInWebView1 {
    NSString *path = [[NSBundle mainBundle] pathForResource:IMAGE_NAME ofType:IMAGE_TYPE];
    NSData *gifData = [NSData dataWithContentsOfFile:path];
    UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(contentRect.origin.x, contentRect.origin.y, contentRect.size.width/2, contentRect.size.height/2)];
    //禁止回弹
    webView.scrollView.bounces = NO;
    webView.scrollView.scrollEnabled = NO;
    webView.scalesPageToFit = YES;
    //设置透明背景(webview的默认背景上灰色的)
    webView.backgroundColor = [UIColor clearColor];
    webView.opaque = 0;
    //禁止交互
    webView.userInteractionEnabled = NO;
    [webView loadData:gifData MIMEType:@"image/gif" textEncodingName:@"UTF-8" baseURL:[NSURL fileURLWithPath:@""]];
    [self.view addSubview:webView];
}

-(void)loadGifInWebView2 {
    NSURL *resourceUrl = [NSBundle mainBundle].resourceURL;
    NSString *html = [NSString stringWithFormat:@"<html><body><img src=\"%@.%@\"></body></html>", IMAGE_NAME, IMAGE_TYPE];
    UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(contentRect.origin.x+contentRect.size.width/2, contentRect.origin.y, contentRect.size.width/2, contentRect.size.height/2)];
    [webView loadHTMLString:html baseURL:resourceUrl];
    [self.view addSubview:webView];
}

//普通的UIImage只能显示gif图片的第一帧
-(void)loadGifInImageView {
    NSArray *gifImageNameArray = [[NSArray alloc] initWithObjects:@"1",@"5",@"10",@"16", nil];
    NSMutableArray *gifImageArray = [NSMutableArray array];
    for(int i=0; i<gifImageNameArray.count; i++) {
        NSString *name = [NSString stringWithFormat:@"resource/gif/%@", [gifImageNameArray objectAtIndex:i]];
        NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"jpg"];
        UIImage *image = [UIImage imageWithContentsOfFile:path];
        [gifImageArray addObject:image];
    }
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(contentRect.origin.x, contentRect.origin.y+contentRect.size.height/2, contentRect.size.width/2, contentRect.size.height/2)];    [self.view addSubview:imageView];
    imageView.animationImages = gifImageArray;
    //动画执行的总时长
    imageView.animationDuration = 4*0.15;
    //动画重复次数(0为重复播放)
    imageView.animationRepeatCount = 0;
    [imageView startAnimating];
    /*
     typedef NS_ENUM(NSInteger, UIViewContentMode) {
     UIViewContentModeScaleToFill,
     UIViewContentModeScaleAspectFit,      // contents scaled to fit with fixed aspect. remainder is transparent
     UIViewContentModeScaleAspectFill,     // contents scaled to fill with fixed aspect. some portion of content may be clipped.
     UIViewContentModeRedraw,              // redraw on bounds change (calls -setNeedsDisplay)
     UIViewContentModeCenter,              // contents remain same size. positioned adjusted.
     UIViewContentModeTop,
     UIViewContentModeBottom,
     UIViewContentModeLeft,
     UIViewContentModeRight,
     UIViewContentModeTopLeft,
     UIViewContentModeTopRight,
     UIViewContentModeBottomLeft,
     UIViewContentModeBottomRight,
     };
     */
    imageView.contentMode = UIViewContentModeScaleToFill;
    //imageView.contentMode = UIViewContentModeScaleAspectFit;
    //imageView.contentMode = UIViewContentModeScaleAspectFill;
    //imageView.contentScaleFactor = [UIScreen mainScreen].scale;
    //imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    imageView.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:imageView];
}

-(void)loadGifInGifView {
    NSString *path = [[NSBundle mainBundle] pathForResource:IMAGE_NAME ofType:IMAGE_TYPE];
    GifView *gifView = [[GifView alloc] initWithFrame:CGRectMake(contentRect.origin.x+contentRect.size.width/2, contentRect.origin.y+contentRect.size.height/2, contentRect.size.width/2, contentRect.size.height/2) gifFileURL:[NSURL fileURLWithPath:path]];
    //[gifView startGif];
    [self.view addSubview:gifView];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
 

2、GifView.h

//
//  GifView.h
//  GifDemo
//
//  Created by 555chy on 6/18/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <ImageIO/ImageIO.h>
#import <QuartzCore/QuartzCore.h>

@interface GifView : UIImageView

-(id) initWithFrame:(CGRect)frame gifFileURL:(NSURL *)fileURL;
-(BOOL) startGif;
-(void) stopGif;

@end

3、GifView.m

//
//  GifView.m
//  GifDemo
//
//  Created by 555chy on 6/18/16.
//  Copyright © 2016 555chy. All rights reserved.
//

#import "GifView.h"

void getFrameInfo(CFURLRef url, NSMutableArray *frames, NSMutableArray *delayTimes, CGFloat *totalTime, CGFloat *gifWidth, CGFloat *gifHeight) {
    CGImageSourceRef gifSource = CGImageSourceCreateWithURL(url, NULL);
    size_t frameCount = CGImageSourceGetCount(gifSource);
    NSLog(@"gif frame count = %ld", frameCount);
    
    for(size_t i=0; i<frameCount; i++) {
        //get each frame
        CGImageRef frame = CGImageSourceCreateImageAtIndex(gifSource, i, NULL);
        //[frames addObject:(id)frame];
        //Cast of C pointer type 'CGImageRef' (aka 'struct CGImage *') to Objective-C pointer type 'id' requires a bridged cast
        [frames addObject:(id)CFBridgingRelease(frame)];
        //这边不需要手动释放了,因为CFBridgingRelease已经把管理权交给ARC了
        //CGImageRelease(frame);
        
        //get gif info with each frame
        //Cast of C pointer type 'CGImageRef' (aka 'struct CGImage *') to Objective-C pointer type 'id' requires a bridged cast
        //NSDictionary *dict = (NSDictionary*)CGImageSourceCopyPropertiesAtIndex(gifSource, i, NULL);
        NSDictionary *dict = (NSDictionary*)CFBridgingRelease(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];
            NSLog(@"%ld. gif width*height = %f*%f", i, *gifWidth, *gifHeight);
        }
        
        //get gif property
        NSDictionary *gifPropertyDict = [dict valueForKey:(NSString*)kCGImagePropertyGIFDictionary];
        
        //kCGImagePropertyGifDictionary中kCGImagePropertyGIFDelayTime, kCGImagePropertyGIFUnclampedDelayTime的值是一样的
        id delayTimeObj = [gifPropertyDict valueForKey:(NSString*)kCGImagePropertyGIFDelayTime];
        NSLog(@"delayTimeObject = %@", delayTimeObj);
        [delayTimes addObject:delayTimeObj];
        id unclampedDelayTimeObj = [gifPropertyDict valueForKey:(NSString*)kCGImagePropertyGIFUnclampedDelayTime];
        NSLog(@"unclampedDelayTimeObj = %@", unclampedDelayTimeObj);
        //[delayTimes addObject:unclampedDelayTimeObj];
        
        if(totalTime) {
            *totalTime = *totalTime + [delayTimeObj floatValue];
        }
    }
    NSLog(@"totalTime = %f", *totalTime);
    CFRelease(gifSource);
}

@interface GifView() {
    NSMutableArray *_gifFrames;
    NSMutableArray * _gifFrameDelayTimes;
    
    CGFloat _gifTotalTime;
    CGFloat _gifWidth;
    CGFloat _gifHeight;
}
@end

@implementation GifView

- (id) initWithFrame:(CGRect)frame gifFileURL:(NSURL *)fileURL {
    self = [super initWithFrame:frame];
    if(self) {
        _gifFrames = [[NSMutableArray alloc] init];
        _gifFrameDelayTimes = [[NSMutableArray alloc] init];
        
        _gifWidth = 0;
        _gifHeight = 0;
        
        if(fileURL) {
            getFrameInfo((__bridge CFURLRef) fileURL, _gifFrames, _gifFrameDelayTimes, &_gifTotalTime, &_gifWidth, &_gifHeight);
        }
    }
    return self;
}

- (BOOL) startGif
{
    CGFloat currentTime = 0;
    unsigned int count = (unsigned int)_gifFrameDelayTimes.count;
    NSLog(@"gif frame count = %u", count);
    if(count <= 0 || _gifTotalTime <= 0) {
        return NO;
    }
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
    
    NSMutableArray *times = [NSMutableArray arrayWithCapacity:count];
    for(unsigned int i=0; i<count; i++) {
        [times addObject:[NSNumber numberWithFloat:(currentTime/_gifTotalTime)]];
        currentTime += [[_gifFrameDelayTimes objectAtIndex:i] floatValue];
    }
    [animation setKeyTimes:times];
    
    NSMutableArray *images = [NSMutableArray arrayWithCapacity:count];
    for(unsigned int i=0; i<count; i++) {
        NSString *path = [[NSBundle mainBundle] pathForResource:@"resource/gif/1" ofType:@"jpg"];
        UIImage *image = [UIImage imageWithContentsOfFile:path];
        [images addObject:image];
        //[images addObject:[_gifFrames objectAtIndex:i]];
    }
    [animation setValues: images];
    
    //[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
    animation.duration = _gifTotalTime;
    animation.delegate = self;
    /* The repeat count of the object. May be fractional. Defaults to 0. */
    animation.repeatCount = 5;
    [self.layer addAnimation:animation forKey:@"gifAnimation"];

    return YES;
}

- (void) stopGif {
    [self.layer removeAllAnimations];
}

- (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


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值