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

【iOS】UIImageView支持GIF动画

程序员文章站 2024-01-19 12:36:52
...

项目中经常会用到SDWebImage来缓存图片,但是最新版本的SDWebImage似乎对GIF分类做出了改变,仅支持NSData,但把图片文件转换为NSData后再用SDWebImage提供的GIF方法,貌似并不管用(没有动画效果),现在把之前的GIF分类贴上来,供大家参考使用:

UIImage+YBGIF.h

#import <UIKit/UIKit.h>

@interface UIImage (YBGIF)
/**
 根据图片名字创建gif图片

 @param name 图片名字
 @return UIImage*
 */
+ (UIImage *)animatedGIFNamed:(NSString *)name;

/**
 根据NSData* 创建gif图片

 @param data NSData *
 @return UIImage *
 */
+ (UIImage *)animatedGIFWithData:(NSData *)data;

/**
 根据大小裁剪图片

 @param size 裁剪大小
 @return UIImage*
 */
- (UIImage *)animatedImageByScalingAndCroppingToSize:(CGSize)size;


UIImage+YBGIF.m

#import "UIImage+YBGIF.h"
#import <ImageIO/ImageIO.h>

@implementation UIImage (YBGIF)
+ (UIImage *)animatedGIFWithData:(NSData *)data {
   if (!data) {
       return nil;
   }
   
   CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
   
   size_t count = CGImageSourceGetCount(source);
   
   UIImage *animatedImage;
   
   if (count <= 1) {
       animatedImage = [[UIImage alloc] initWithData:data];
   }
   else {
       NSMutableArray *images = [NSMutableArray array];
       
       NSTimeInterval duration = 0.0f;
       
       for (size_t i = 0; i < count; i++) {
           CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
           if (!image) {
               continue;
           }
           
           duration += [self frameDurationAtIndex:i source:source];
           
           [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
           
           CGImageRelease(image);
       }
       
       if (!duration) {
           duration = (1.0f / 10.0f) * count;
       }
       
       animatedImage = [UIImage animatedImageWithImages:images duration:duration];
   }
   
   CFRelease(source);
   
   return animatedImage;
}

+ (float)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
   float frameDuration = 0.1f;
   CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
   NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
   NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary];
   
   NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
   if (delayTimeUnclampedProp) {
       frameDuration = [delayTimeUnclampedProp floatValue];
   }
   else {
       
       NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime];
       if (delayTimeProp) {
           frameDuration = [delayTimeProp floatValue];
       }
   }
   
   // Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
   // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify
   // a duration of <= 10 ms. See <rdar://problem/7689300> and <http://webkit.org/b/36082>
   // for more information.
   
   if (frameDuration < 0.011f) {
       frameDuration = 0.100f;
   }
   
   CFRelease(cfFrameProperties);
   return frameDuration;
}

+ (UIImage *)animatedGIFNamed:(NSString *)name {
   CGFloat scale = [UIScreen mainScreen].scale;
   
   if (scale > 1.0f) {
       NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"];
       
       NSData *data = [NSData dataWithContentsOfFile:retinaPath];
       
       if (data) {
           return [UIImage animatedGIFWithData:data];
       }
       
       NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
       
       data = [NSData dataWithContentsOfFile:path];
       
       if (data) {
           return [UIImage animatedGIFWithData:data];
       }
       
       return [UIImage imageNamed:name];
   }
   else {
       NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];
       
       NSData *data = [NSData dataWithContentsOfFile:path];
       
       if (data) {
           return [UIImage animatedGIFWithData:data];
       }
       
       return [UIImage imageNamed:name];
   }
}

- (UIImage *)animatedImageByScalingAndCroppingToSize:(CGSize)size {
   if (CGSizeEqualToSize(self.size, size) || CGSizeEqualToSize(size, CGSizeZero)) {
       return self;
   }
   
   CGSize scaledSize = size;
   CGPoint thumbnailPoint = CGPointZero;
   
   CGFloat widthFactor = size.width / self.size.width;
   CGFloat heightFactor = size.height / self.size.height;
   CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor : heightFactor;
   scaledSize.width = self.size.width * scaleFactor;
   scaledSize.height = self.size.height * scaleFactor;
   
   if (widthFactor > heightFactor) {
       thumbnailPoint.y = (size.height - scaledSize.height) * 0.5;
   }
   else if (widthFactor < heightFactor) {
       thumbnailPoint.x = (size.width - scaledSize.width) * 0.5;
   }
   
   NSMutableArray *scaledImages = [NSMutableArray array];
   
   for (UIImage *image in self.images) {
       UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
       
       [image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)];
       UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
       
       [scaledImages addObject:newImage];
       
       UIGraphicsEndImageContext();
   }
   
   return [UIImage animatedImageWithImages:scaledImages duration:self.duration];
}

@end