[英]iOS solution to load images with animation only if they are not already cached in memory with SDWebImage
我幾天來一直在努力解決這個問題。 以前我使用AFNetworking類來加載和緩存圖像,但它沒有在它的回調中提供緩存類型。 所以我曾經在每個控制器中跟蹤哪些圖像已經加載。 我瀏覽了SDWebImage,它提供了我正在尋找的東西 - SDImageCacheType
。
現在我試圖想出一個易於使用(希望是一個單行)的解決方案來加載表格和集合視圖中的圖像,如果它們被下載或來自磁盤緩存。 基本上這些任務需要一些時間才能獲得實際圖像,當內存緩存瞬間提供圖像時,因此當圖像來自內存時不需要動畫。
我想出了這個UIImageView類別,我希望有更有經驗的人提供一些反饋。 它確實似乎按預期工作。 我不確定我是在這里重新發明輪子,否則這種做法在某些情況下可能會適得其反。
概述是做兩件事。 在完成塊中,當圖像准備好使用時,它根據已使用的緩存級別設置動畫持續時間。 第二個想法是可重復使用的單元機制,imageView在相關對象的幫助下跟蹤加載操作,如果有正在進行的任務則取消它。 AFNetworking解決方案不需要這樣做,因為當您設置新的解決方案時,它會默認取消正在進行的圖像加載。 我不喜歡這樣的事實,即操作被保留,它不應該是,但是關聯的對象不提供__weak
類型的引用afaik。 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;
}
--- UPDATE ---
在@ 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;
}
}
}];
}
我偶然發現了這一點,並且已經在各種項目中做到了這一點。 這里的關鍵是阻止圖像自動設置的選項。 然后我們檢查緩存類型並做一個很棒的交叉淡入淡出。 您還可以在加載內容時設置占位符圖像,或者如果在加載某些內容時需要純色背景,則可以設置圖像視圖的背景顏色。
[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];
}
}
}];
您使用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仍然會引入整個動畫操作的開銷,這不僅會降低性能,還會增加一點延遲,否則會沒有動畫就看不到。
使用這里列出的答案,我能夠為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)
})
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.