我几天来一直在努力解决这个问题。以前我使用AFNetworking类来加载和缓存图像,但它没有在其回调中提供缓存类型。所以我曾经在每个控制器中跟踪哪些图像已经加载。我查看了SDWebImage,它提供了我正在寻找的内容 - SDImageCacheType
。
现在,我试图提出一个易于使用(希望是一个单行)的解决方案,如果下载或来自磁盘缓存,则可以使用动画在表格和集合视图中加载图像。基本上这些任务需要一些时间来获取实际图像,当内存缓存瞬间提供图像时,因此当图像来自内存时不需要动画。
我已经提出了这个UIImageView类别,我希望有更有经验的人提供一些反馈。它确实似乎按预期工作。我不确定我是否在这里重新发明轮子,否则这种做法在某些情况下可能会适得其反。
概述是两件事分开。在完成块中,当图像准备好使用时,它根据已使用的缓存级别设置动画持续时间。第二个想法是可重复使用的单元机制,imageView在相关对象的帮助下跟踪加载操作,如果有正在进行的任务则取消它。 AFNetworking解决方案不需要这样做,因为当您设置新的解决方案时,它会默认取消正在进行的图像加载。
我不喜欢这样的事实,即该操作是保留的,它不应该是,但是相关的对象不能提供__weak
类型的参考。 OBJC_ASSOCIATION_ASSIGN
密钥似乎会使对象__unsafe_unretained
导致访问崩溃。
任何建议都将受到赞赏。
static char kOperationKey;
- (id <SDWebImageOperation>)scrb_setImageAnimatedWithURL:(NSURL *)url {
id <SDWebImageOperation> lastOperation = objc_getAssociatedObject(self, &kOperationKey);
if (lastOperation) {
[lastOperation cancel];
}
id <SDWebImageOperation> operation = [[SDWebImageManager sharedManager] downloadImageWithURL:url options:SDWebImageRetryFailed progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
if (finished && image) {
BOOL animated = NO;
if (cacheType == SDImageCacheTypeDisk || cacheType == SDImageCacheTypeNone) {
animated = YES;
}
if (animated) {
[UIView transitionWithView:self duration:ANIMATION_DURATION options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
self.image = image;
} completion:nil];
} else {
self.image = image;
}
}
}];
objc_setAssociatedObject(self, &kOperationKey, operation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return operation;
}
---更新---
在 @ n00neimp0rtant 的帮助下,我已将我的类别更改为:
- (void)scrb_setImageAnimatedWithURL:(NSURL *)url {
[self sd_cancelCurrentImageLoad];
self.alpha = 0.0;
[self sd_setImageWithURL:url placeholderImage:nil options:SDWebImageRetryFailed completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (image) {
BOOL animated = NO;
if (cacheType == SDImageCacheTypeDisk || cacheType == SDImageCacheTypeNone) {
animated = YES;
}
self.image = image;
if (animated) {
[UIView animateWithDuration:ANIMATION_DURATION animations:^{
self.alpha = 1.0;
}];
} else {
self.alpha = 1.0;
}
}
}];
}
答案 0 :(得分:5)
我偶然发现了这一点,并且已经在各种项目中这样做了。这里的关键是阻止图像自动设置的选项。然后我们检查缓存类型并做一个很棒的交叉淡入淡出。您还可以在加载内容时设置占位符图像,或者在加载某些内容时设置纯色背景时设置图像视图的背景颜色。
[self.mediaImage sd_setImageWithURL:[NSURL URLWithString:content.previewUrl]
placeholderImage:nil
options:SDWebImageAvoidAutoSetImage
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if ([imageURL isEqual:[NSURL URLWithString:content.previewUrl]]) {
if (cacheType == SDImageCacheTypeMemory) {
self.mediaImage.image = image;
} else {
[UIView transitionWithView:self.mediaImage
duration:.3
options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
self.mediaImage.image = image;
}
completion:nil];
}
}
}];
答案 1 :(得分:3)
您使用SDWebImageManager手动下载图像的任何特殊原因? SDWebImage已经为UIImageView类提供了可以在UIImageView上直接调用的方法。
这就是我解决问题的方法:
#import <UIImageView+WebCache.h>
// let's say we wanted to do a fade-in animation
imageView.alpha = 0.f;
[imageView sd_setImageWithURL:url completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (cacheType == SDImageCacheTypeNone) {
[UIView animateWithDuration:0.3 animations:^{
imageView.alpha = 1.f;
}];
} else {
imageView.alpha = 1.f;
}
}];
另外,作为旁注,执行持续时间为0.0的动画可能在逻辑上是瞬时的,但iOS仍然会引入整个动画操作的开销,这不仅会降低性能,还会增加一点延迟没有动画,否则你不会看到。
答案 2 :(得分:2)
使用此处列出的答案,我能够为swift组建一个版本。
imageView.sd_setImage(with: imageURL, placeholderImage: imageView.image, options: .avoidAutoSetImage, completed: { (image, error, cache, url) in
UIView.transition(with: self, duration: 1.35, options: .transitionCrossDissolve, animations: {
self.imageView.image = image
}, completion: nil)
})