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。當然,這完全根據實際情況而定。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章