工作的时候,需要播放某几帧有延时的GIF,才发现工程中接入的SDWebImage(V3.8)不支持这个功能。
某一些帧有明显延时 (网络图片,侵删)
为了解决这个问题,查了一些资料,看了SDWebImage源码,所以做个记录:在4.0之前,SDWebImage自带GIF播放效果,不需要特殊处理;从4.0开始,SDWebImage集成FLAnimatedImageView来播放GIF。
V4.0之前
SDWebImage源码里面,对于获取到的图片信息(二进制数据),如果判定为GIF,就换成GIF图:
+ (UIImage *)sd_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;
}
//获取每一帧的展示时长,并相加,得到整个GIF的时长
duration += [self sd_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;
}
如上所示,整个GIF的duration是每一帧的展示时长相加之和,从而导致最终每一帧展示的时长是一样的。对于普通的GIF,可以满足需求,但是对于那些某一帧需要特别停顿较长时间的GIF,就满足不了需求。
不过,这个版本中,SDWebImage外露的下载GIF和普通图片(png、JPG等)的接口是一致的。所以,使用者不用区分需要下载的是GIF还是普通图片,使用统一的接口下载即可。
V4.0及以上
从4.0开始,SDWebImage集成了FLAnimatedImageView,并且新建了一个FLAnimatedImageView的分类,专门用于播放GIF:
FLAnimatedImageView的分类
如果想要下载的是GIF,那么对应的UIImageView必须FLAnimatedImageView的对象,并且使用FLAnimatedImageView+WebCache提供的接口:
FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init];
imageView.frame = CGRectMake(100, 300, 38, 38);
[imageView sd_setImageWithURL:[NSURL URLWithString:@"https://www.xxx.com/xxx.gif"] placeholderImage:nil options:SDWebImageRefreshCached];
[self.view addSubview:imageView];
而且,FLAnimatedImageView里面,使用了CADisplayLink作为计时器来播放GIF,从而可以达到每一帧时长都不同的效果。
分析
个人觉得,4.0之所以集成FLAnimatedImageView,主要就是为了可以播放每一帧的展示时长会不同的GIF。