iOS优雅的展示GIF动图2----UIImage

开篇语:

上一篇我们介绍了如何使用FLAnimatedImage类库加载gif动画,但是,当我们采用了此方案之后发现,牵连的地方还真不少。首先,所有UIImageView都需要更换一边。其次以往传递UIImage的地方需要换成FLAnimatedImage,这修改量可就大了。如何才能继续优雅的使用UIImage呢?

UIImage:

实际上,UIImage是支持创建动图的,但是方法有些个性:

+ (nullable UIImage *)animatedImageWithImages:(NSArray<UIImage *> *)images duration:(NSTimeInterval)duration NS_AVAILABLE_IOS(5_0);

可以看到初始化时需要传递一个UIImage的数组。那么这个数组从何而来呢?这就涉及到如何提取gif每一帧的图片啦。当然这类代码很多,例如3.X版本的SDWebImage就有相关的代码。

参考代码:

/**
 初始化UIImage动图

 @param data gif资源
 @param scale 缩放比例
 @return UIImage动图
 */
+ (UIImage *)animatedImageWithData:(NSData *)data scale:(CGFloat)scale {
    if (!data) {
        return nil;
    }
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    size_t count = CGImageSourceGetCount(source);
    UIImage *animatedImage = nil;
    if (count <= 1) {
        animatedImage = [[UIImage alloc] initWithData:data];
    } else {
        NSMutableArray<UIImage *> *images = [[NSMutableArray alloc] init];
        NSTimeInterval duration = 0.0f;
        for (size_t i = 0; i < count; i++) {
            CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
            duration += [self frameDurationAtIndex:i source:source];
            UIImage *frameImage = [UIImage imageWithCGImage:image scale:scale orientation:UIImageOrientationUp];
            [images addObject:frameImage];
            CGImageRelease(image);
        }
        if (!duration) {
            duration = (1.0f / 10.0f) * count;
        }
        animatedImage = [UIImage animatedImageWithImages:images duration:duration];
    }
    CFRelease(source);
    return animatedImage;
}

/**
 The duration of the animation.
 */
+ (float)frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source {
    float frameDuration = 0.1f;
    CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil);
    NSDictionary<NSString *, NSDictionary *> *frameProperties = (__bridge NSDictionary *)cfFrameProperties;
    NSDictionary<NSString *, NSNumber *> *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];
        }
    }
    CFRelease(cfFrameProperties);
    return frameDuration;
}

此时有了可以动的UIImage,那相应的UIImageView就不用再动代码啦。

下面我们来看看如果优雅的结合SDWebImage(主要是考虑使用它的异步网络加载、内存管理等优秀特点)。

//这里省略初始化UIImageView的代码
NSURL *imageUrl = [NSURL URLWithString:@"http://demo.gif"];

//在SDWebImage的setImageBlock块中处理GIF逻辑
[imageView sd_internalSetImageWithURL:imageUrl placeholderImage:nil options:0 operationKey:nil setImageBlock:^(UIImage * _Nullable image, NSData * _Nullable imageData) {
    //避免闪屏,先赋值一下
    imageView.image = image;
    //这里判断GIF资源图片
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        __block NSData *gifData = imageData;
        if (!gifData) {
            //得到缓存
            NSString *key = [[SDWebImageManager sharedManager] cacheKeyForURL:imageUrl];
            gifData = [[SDImageCache sharedImageCache] diskImageDataForKey:key];
        }
        UIImage *animatedImage = [UIImage animatedImageWithData:gifData];
        //如果是GIF图的话,再赋值
        if (animatedImage.images) {
            dispatch_async(dispatch_get_main_queue(), ^{
                imageView.image = animatedImage;
            });
        }
    });
} progress:nil completed:nil];

这里注意,gifData可能是空值,需要我们去缓存管理器中主动获取一下。

总结:

FLAnimatedImage确实是加载gif图片的好方法,但有时候考虑到后期维护、扩展性等方面,我们不得不屈服现实代码。最后项目中我们选择了UIImage。当然,这完全根据实际情况而定。

 

 

猜你喜欢

转载自blog.csdn.net/xuexixiaoshizhe/article/details/84973981