支持 GIF 的圖片組件 BBWebImagehtml
SDWebImage 4.0 以前,能夠用 UIImageView 顯示 GIF 圖。若是 SDWebImage 4.0 還這麼作,只會顯示靜態圖。SDWebImage 4.0 用 FLAnimatedImageView 經過 FLAnimatedImage 顯示 GIF 圖。本文的這兩個庫的版本分別爲 SDWebImage 4.0.0 和 FLAnimatedImage 1.0.12。git
pod 'SDWebImage' pod 'SDWebImage/GIF'
用 FLAnimatedImageView 代替 UIImageView,顯示 GIF。FLAnimatedImage 的 README.md 中介紹的用法github
FLAnimatedImage *image = [FLAnimatedImage animatedImageWithGIFData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif"]]]; FLAnimatedImageView *imageView = [[FLAnimatedImageView alloc] init]; imageView.animatedImage = image; imageView.frame = CGRectMake(0.0, 0.0, 100.0, 100.0); [self.view addSubview:imageView];
千萬別這麼寫,這段代碼會阻塞主線程!在主線程經過 URL 獲取 NSData,等下載結束才執行下一步。web
FLAnimatedImageView 的用法和 UIImageView 類似,初始化、設置 frame、添加到視圖上、用 UIImage 給 image 屬性賦值顯示靜態圖片;不同的是,用 FLAnimatedImage 給 animatedImage 屬性賦值顯示動態圖片。以上代碼的問題在於 FLAnimatedImage 的生成部分。swift
SDWebImage 給 FLAnimatedImageView 添加了異步加載 GIF 的方法,與異步加載靜態圖片同樣異步
imageView.sd_setImage(with: url, placeholderImage: placeholder)
若是顯示少許的 GIF,這樣寫應該能夠。然而,若是須要用 UITableView 或 UICollectionView 展現大量 GIF,這麼寫可能會有性能問題,滑動時發生頓卡。async
爲了提升性能,能夠指定 RunLoopMode,在 default mode 進行動畫,在 tracking mode (好比 scroll view 滑動時) 中止動畫oop
imageView.runLoopMode = RunLoopMode.defaultRunLoopMode.rawValue
個人代碼中,這麼寫仍是會有頓卡。查看 SDWebImage 的源碼,發現了問題。性能
sd_setImage(with:placeholderImage:) 會調用 sd_internalSetImageWithURL: 方法動畫
注意,sd_internalSetImageWithURL: 方法中的 setImageBlock 參數,在今生成 FLAnimatedImage。進一步查看 sd_internalSetImageWithURL: 方法的實現
宏定義 dispatch_main_async_safe(block) 保證 block 在主線程中執行,其中包含 setImageBlock。所以 setImageBlock 在主線程中執行,也就是說 FLAnimatedImage 在主線程中生成,這一步比較耗時,阻塞主線程,形成頓卡。
解決辦法是,把 FLAnimatedImage 的生成放到子線程中。能夠直接修改 SDWebImage 的源碼,但不建議這麼作。比較好的辦法是,給 FLAnimatedImageView 添加方法
extension FLAnimatedImageView { func setImage(with url: URL?, placeholderImage: UIImage?) { sd_internalSetImage(with: url, placeholderImage: placeholderImage, options: SDWebImageOptions(rawValue: 0), operationKey: nil, setImageBlock: { [weak self] (image, imageData) in guard let strongSelf = self else { return } let imageFormat = NSData.sd_imageFormat(forImageData: imageData) if imageFormat == .GIF { // Enter global queue DispatchQueue.global(qos: .userInteractive).async { [weak self] in // Create FLAnimatedImage in global queue let animatedImage = FLAnimatedImage(animatedGIFData: imageData) DispatchQueue.main.async { [weak self] in guard let strongSelf = self else { return } // Set image in main queue strongSelf.animatedImage = animatedImage strongSelf.image = nil } } } else { // Set image in main queue strongSelf.image = image strongSelf.animatedImage = nil } }, progress: nil, completed: nil) } }
一樣調用 sd_internalSetImageWithURL: 方法,只是修改 setImageBlock 參數,在子線程中建立 FLAnimatedImage,而後在主線程中設置圖片。
這個方法也適用於靜態圖片。若是圖片是靜態圖片,直接在主線程中設置圖片,不用進入子線程。
調用這個方法很簡單
imageView.setImage(with: url, placeholderImage: placeholder)
這樣寫,UITableView 滑動就很流暢了。
代碼已上傳 GitHub:https://github.com/Silence-GitHub/GIFDemo
這個解決方案雖然能用,可是從設計的角度看,SDWebImage 使用 FLAnimatedImage 並不合適。有興趣能夠試試支持 GIF 的圖片組件 BBWebImage
轉載請註明出處:http://www.cnblogs.com/silence-cnblogs/p/6682867.html