作者:无语我去_296 | 来源:互联网 | 2023-06-02 15:30
在 iOS 开发中说到指示器用的最多的便是 MBP 和 SVP 了,针对于这两个第三方我个人还是比较偏向后者。比较 MBP 而言 SVP的作者封装的更加完美一些,接口的设计和使用也更为简单,但是在使用时还是有些场景无法满足,这篇文章我只是想谈谈对于把自定义的 GIF 图片与 SVProgressHUD 结合使用的个人想法。首先我们先看看下面的一段代码:
- (void)viewDidLoad {[super viewDidLoad];// 我们通过 SVProgressHUD 提供的类方法 + (void)show; 可以实现最简单的加载指示效果[SVProgressHUD show];}- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{// 移除指示器[SVProgressHUD dismiss];
}
效果图如下 :
方案一:通过属性实现
- (void)viewDidLoad {[super viewDidLoad];// 设置显示最小时间 以便观察效果[SVProgressHUD setMinimumDismissTimeInterval:MAXFLOAT];// 设置属性 @property (strong, nonatomic) UIImage *infoImage [SVProgressHUD setInfoImage:[UIImage imageNamed:@"testImage@2x.gif"]];[SVProgressHUD showInfoWithStatus:@"努力加载中"];}
但是效果却不是我们想要的,我们发现原本是 Gif 可以转动的图片不能动了... 效果如下 :
其实 Gif 图片能动的本质是帧动画,我们在利用软件制作 Gif 图片的时候中间有一个步骤是 : 比如将一个小视频分割成N张图片,然后按照每张图片设置好的帧时长来进行连贯播放,优化后就形成了我们所熟知的 Gif 图片了。那么我们在 iOS 开发过程中能否将原有的 Gif 图片转换为N张静态图片的数组,再由 UIImage 提供的帧动画方法生成可以动的 UIImage对象。根据这个想法,我写了下面的一个分类 :
UIImage+GIF.h
#import
typedef void (^GIFimageBlock)(UIImage *GIFImage);@interface UIImage (GIF)/** 根据本地GIF图片名 获得GIF image对象 */
+ (UIImage *)imageWithGIFNamed:(NSString *)name;/** 根据一个GIF图片的data数据 获得GIF image对象 */
+ (UIImage *)imageWithGIFData:(NSData *)data;/** 根据一个GIF图片的URL 获得GIF image对象 */
+ (void)imageWithGIFUrl:(NSString *)url and:(GIFimageBlock)gifImageBlock;@end
UIImage+GIF.m
#import "UIImage+GIF.h"
#import @implementation UIImage (GIF)+ (UIImage *)imageWithGIFData:(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 }+ (UIImage *)imageWithGIFNamed:(NSString *)name
{NSUInteger scale = (NSUInteger)[UIScreen mainScreen].scale;return [self GIFName:name scale:scale];
}+ (UIImage *)GIFName:(NSString *)name scale:(NSUInteger)scale
{NSString *imagePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@@%zdx", name, scale] ofType:@"gif"];if (!imagePath) {(scale + 1 > 3) ? (scale -= 1) : (scale += 1);imagePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@@%zdx", name, scale] ofType:@"gif"];}if (imagePath) {// 传入图片名(不包含@Nx)NSData *imageData = [NSData dataWithContentsOfFile:imagePath];return [UIImage imageWithGIFData:imageData];} else {imagePath = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"];if (imagePath) {// 传入的图片名已包含@Nx or 传入图片只有一张 不分@NxNSData *imageData = [NSData dataWithContentsOfFile:imagePath];return [UIImage imageWithGIFData:imageData];} else {// 不是一张GIF图片(后缀不是gif)return [UIImage imageNamed:name];}}
}+ (void)imageWithGIFUrl:(NSString *)url and:(GIFimageBlock)gifImageBlock
{NSURL *GIFUrl = [NSURL URLWithString:url];if (!GIFUrl) return;dispatch_async(dispatch_get_global_queue(0, 0), ^{NSData *CIFData = [NSData dataWithContentsOfURL:GIFUrl];// 刷新UI在主线程dispatch_async(dispatch_get_main_queue(), ^{gifImageBlock([UIImage imageWithGIFData:CIFData]);});});}#pragma mark - <关于GIF图片帧时长(Learning...)>+ (float)sd_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&#39;s behavior and use a duration of 100 ms for any frames that specify// a duration of <= 10 ms. See and // for more information.if (frameDuration <0.011f) {frameDuration = 0.100f;}CFRelease(cfFrameProperties);return frameDuration;
}
那么引入这个分类,我们看看是否能达到预期的效果,代码 AND 效果图如下 :
- (void)viewDidLoad {[super viewDidLoad];// 设置显示最小时间 以便观察效果[SVProgressHUD setMinimumDismissTimeInterval:MAXFLOAT];// 设置背景颜色为透明色[SVProgressHUD setBackgroundColor:[UIColor clearColor]];// 利用SVP提供类方法设置 通过UIImage分类方法返回的动态UIImage对象[SVProgressHUD showImage:[UIImage imageWithGIFNamed:@"loading01"] status:@"正在加载中"];}
效果图如下 :
至此我们简单的实现了,使用 SVProgressHUD 时加入我们自定义的 Gif 图片。大家有更好的方法也可以相互讨论,共同提高,谢谢支持我的博客 : http://blog.csdn.net/im_loser 。