眾所周知绰寞,在SDWebImage框架下想要對圖片在下載和下載過程中的狀態(tài)進(jìn)行處理,需要使用SDWebImageOptions
泉手,我們首先看一下SDWebImage中有哪些可選項(xiàng)
typedef NS_OPTIONS(NSUInteger, SDWebImageOptions) {
/**
* By default, when a URL fail to be downloaded, the URL is blacklisted so the library won't keep trying.
* This flag disable this blacklisting.
*/
SDWebImageRetryFailed = 1 << 0,
/**
* By default, image downloads are started during UI interactions, this flags disable this feature,
* leading to delayed download on UIScrollView deceleration for instance.
*/
SDWebImageLowPriority = 1 << 1,
/**
* This flag disables on-disk caching
*/
SDWebImageCacheMemoryOnly = 1 << 2,
/**
* This flag enables progressive download, the image is displayed progressively during download as a browser would do.
* By default, the image is only displayed once completely downloaded.
*/
SDWebImageProgressiveDownload = 1 << 3,
/**
* Even if the image is cached, respect the HTTP response cache control, and refresh the image from remote location if needed.
* The disk caching will be handled by NSURLCache instead of SDWebImage leading to slight performance degradation.
* This option helps deal with images changing behind the same request URL, e.g. Facebook graph api profile pics.
* If a cached image is refreshed, the completion block is called once with the cached image and again with the final image.
*
* Use this flag only if you can't make your URLs static with embedded cache busting parameter.
*/
SDWebImageRefreshCached = 1 << 4,
/**
* In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for
* extra time in background to let the request finish. If the background task expires the operation will be cancelled.
*/
SDWebImageContinueInBackground = 1 << 5,
/**
* Handles cookies stored in NSHTTPCookieStore by setting
* NSMutableURLRequest.HTTPShouldHandleCookies = YES;
*/
SDWebImageHandleCookies = 1 << 6,
/**
* Enable to allow untrusted SSL certificates.
* Useful for testing purposes. Use with caution in production.
*/
SDWebImageAllowInvalidSSLCertificates = 1 << 7,
/**
* By default, images are loaded in the order in which they were queued. This flag moves them to
* the front of the queue.
*/
SDWebImageHighPriority = 1 << 8,
/**
* By default, placeholder images are loaded while the image is loading. This flag will delay the loading
* of the placeholder image until after the image has finished loading.
*/
SDWebImageDelayPlaceholder = 1 << 9,
/**
* We usually don't call transformDownloadedImage delegate method on animated images,
* as most transformation code would mangle it.
* Use this flag to transform them anyway.
*/
SDWebImageTransformAnimatedImage = 1 << 10,
/**
* By default, image is added to the imageView after download. But in some cases, we want to
* have the hand before setting the image (apply a filter or add it with cross-fade animation for instance)
* Use this flag if you want to manually set the image in the completion when success
*/
SDWebImageAvoidAutoSetImage = 1 << 11
};
可以看出黔寇,最接近我們所需要的「漸變」效果的,就是這個(gè)SDWebImageProgressiveDownload
斩萌,這確實(shí)是一個(gè)逐步顯示圖片的過程缝裤,但是這個(gè)類型所完成的效果,僅僅是一個(gè)從上到下逐漸顯示的效果颊郎,離我們需要的「漸變」效果相差甚遠(yuǎn)憋飞。所以說的直白一些,SDWebImage這個(gè)框架目前是不支持大多數(shù)主流成熟框架均支持的圖片加載「漸變」效果的姆吭。
這樣一來搀崭,要想實(shí)現(xiàn)「漸變」效果,我們似乎只剩下兩條路可以走:
1.替換庫猾编,如YYImage等
- 優(yōu)點(diǎn):框架自帶支持瘤睹,無需使用者自己處理,方便快捷省事
- 缺點(diǎn):顯然答倡,在開發(fā)過程中轰传,突然替換基礎(chǔ)庫的成本是很高的,尤其是在DeadLine為期不遠(yuǎn)的時(shí)候瘪撇。如果團(tuán)隊(duì)中有人不熟悉新庫获茬,那么還會(huì)額外衍生學(xué)習(xí)時(shí)間成本,這對快速迭代來說倔既,是很難接受的一件事
2.對SDWebImage進(jìn)行修改恕曲,手動(dòng)完成對「漸變」效果的支持
- 優(yōu)點(diǎn):節(jié)省了更換其他庫的時(shí)間成本,降低了替換庫所造成的風(fēng)險(xiǎn)和回歸測試的成本
- 缺點(diǎn):可能需要對源代碼進(jìn)行修改渤涌,如果是使用CocoaPods集成的佩谣,那就很麻煩了
這么對比一看,似乎每一條路的成本都不低实蓬,難道真的只剩下這兩條路可以走了嗎茸俭?
答案是: NO
我看到大多數(shù)文章對于SDWebImage實(shí)現(xiàn)漸變效果的處理方式都是修改源碼,這個(gè)做法實(shí)在是太Low了??安皱,任何需要修改成熟開源框架源碼才能完成的事情调鬓,都是最爛的思路和做法
。SDWebImage既然能夠成為適用范圍最廣酌伊,最主流的網(wǎng)絡(luò)圖片框架之一腾窝,其對各種情況和需求的支持力度必然不可能如此局限。即使它不直接支持,那么我們?yōu)楹尾粨Q個(gè)思路和做法呢虹脯?SDWebImage提供的方法如此豐富驴娃,何必要局限于一種,下面我們就來看看如何在不修改SDWebImage源碼的情況下归形,來達(dá)到圖片加載的「漸變」效果托慨,Let's go!
首先,我們不妨可以先思考一下什么是「漸變」效果:無非就是隨著圖片的加載逐漸由模糊到清晰的顯示出來
暇榴,這種效果完全可以通過一個(gè)簡單的CATransition
動(dòng)畫來完成厚棵,唯一的“難點(diǎn)”不過是這個(gè)動(dòng)畫是add和remove的時(shí)機(jī)而已,大多數(shù)此類解決方案都是直接把這個(gè)簡單的動(dòng)畫效果嵌入SDWebImage源碼中蔼紧,這個(gè)做法不僅Low婆硬,而且對SDWebImage源碼也帶來了傷害,最重要的是奸例,如果你繼續(xù)用這個(gè)庫彬犯,難道每次SDWebImage升級你都要再修改一遍源碼嗎,exm???
所以查吊,通過修改SDWebImage源碼來嵌入這種動(dòng)畫的開發(fā)者谐区,幾乎可以肯定,全都是對CAAnimation
基礎(chǔ)完全不熟悉的人逻卖。只要是對CAAnimation
熟悉的開發(fā)者都會(huì)知道宋列,CAAnimationDelegate
協(xié)議中提供了一個(gè)animationDidStop(_ anim: CAAnimation, finished flag: Bool)
方法,該方法可以根據(jù)Animation的key對所有基于CAAnimation
的動(dòng)畫進(jìn)行監(jiān)聽操作评也。這么一來炼杖,我們接下來要做什么,你是不是就很明白了呢盗迟。
我們可以來看一下SDWebImage提供的加載網(wǎng)絡(luò)圖片的方法中坤邪,是有當(dāng)圖片完成后的回調(diào)方法的,如:
/**
* Set the imageView `image` with an `url`, placeholder and custom options.
*
* The download is asynchronous and cached.
*
* @param url The url for the image.
* @param placeholder The image to be set initially, until the image request finishes.
* @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values.
* @param completedBlock A block called when operation has been completed. This block has no return value
* and takes the requested UIImage as first parameter. In case of error the image parameter
* is nil and the second parameter may contain an NSError. The third parameter is a Boolean
* indicating if the image was retrieved from the local cache or from the network.
* The fourth parameter is the original image url.
*/
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock;
我們可以在SDWebImageCompletionBlock
這個(gè)Block塊中來實(shí)現(xiàn)我們的CATransition
動(dòng)畫
/*
* @param options: 選擇.lowPriority(oc中是SDWebImageLowPriority)罚缕,是為了禁止在UI交互過程中啟動(dòng)圖像下載艇纺,保證列表流暢性。例如怕磨,導(dǎo)致UIScrollView減速的下載延遲
*
*
*/
imageView.sd_setImage(with: theUrl as URL, placeholderImage: UIImage.init(named: "newVote_ placeholder"), options: .lowPriority, completed: { [weak self] (image, error, cacheType, url) in
guard let strongSelf = self else { return }
if cacheType == .none { // 只有當(dāng)緩存中沒有圖片喂饥,也就是首次加載時(shí)才實(shí)現(xiàn)CATransition動(dòng)畫
let transition:CATransition = CATransition()
transition.type = kCATransitionFade // 褪色效果,漸進(jìn)效果的基礎(chǔ)
transition.duration = 0.85
transition.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut) // 先慢后快再慢
strongSelf.layer.add(transition, forKey: "newVoteTimeline") // 在layer中加入動(dòng)畫肠鲫,并約定好該動(dòng)畫的key
}
})
我們來解釋一下上面這段代碼究竟做了什么:
options
: 選擇.lowPriority
(oc中是SDWebImageLowPriority
),是為了禁止在UI交互過程中啟動(dòng)圖像下載或粮,保證列表流暢性导饲。例如,導(dǎo)致UIScrollView減速的下載延遲
判斷cacheType == .none
: 只有當(dāng)緩存中沒有圖片,也就是首次加載時(shí)才實(shí)現(xiàn)CATransition動(dòng)畫渣锦,因?yàn)镾DWebImage會(huì)根據(jù)url從緩存中查找是否存在相同的圖片硝岗,只有當(dāng)緩存中不存在該圖片時(shí)才會(huì)啟動(dòng)下載,同理袋毙,我們的「漸變」效果也是只有當(dāng)啟動(dòng)下載是才會(huì)發(fā)生型檀,否則,在列表中復(fù)用時(shí)會(huì)持續(xù)顯示「漸變」效果听盖,無論是否已經(jīng)下載完成
然后胀溺,我們遵循CAAnimationDelegate
協(xié)議,并實(shí)現(xiàn)animationDidStop(_ anim: CAAnimation, finished flag: Bool)
方法:
// MARK: 監(jiān)聽漸變動(dòng)畫是否已完成
func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
if flag {
self.layer.removeAnimation(forKey: "newVoteTimeline") // 當(dāng)newVoteTimeline動(dòng)畫已經(jīng)完成皆看,將其從layer中移除仓坞,避免復(fù)用中的產(chǎn)生反復(fù)「漸變」效果
}
}
以上就完成了針對SDWebImage框架的「漸變」效果修改,幾行代碼即可搞定腰吟,完全不需要對SDWebImage進(jìn)行內(nèi)部修改无埃,有時(shí)候換一種思路思考問題,世界會(huì)豁然開朗毛雇。