http://www.liuhaihua.cn/archives/256577.html
今天我們來學習學習Instrucments之Core Animation之 Color Misaligned Images 。
官方說明是這樣的: Color Misaligned Images: Places a magenta overlay over images where the source pixels are not aligned to the destination pixels.
意思就是當圖片的源像素與目標像素不對齊是會放一個洋紅色的層在圖片上。當圖片的像素大小與控件的大小不一致而導致需要縮放時,圖片會呈現黃色。
本篇文章是記錄筆者學習優化圖片顯示的筆記,同時希望能夠幫助大家進一步學習,當然更希望大家多思考多評論,將自己的想法都在評論中寫出來!
Instrucments Core Animation界面
我們先來說說Instrucments中的選項之一:Core Animation。運行后,默認看到右下角是第一個按鈕,勾選上用于設置監測FPS的:
Color Misaligned Images
而我們根本每一選項做優化,要看下圖,每次只勾選一個,一步步優化:
Color Misaligned Images
優化前
根據官方說明,圖片像素不對齊(也就是圖片帶alpha通道)時,會在圖片上面加一層洋紅色來標識;而圖片被縮放時,會加一層黃色來標識。那么先看看我們的demo中被優化前的UI:
Color Misaligned Images
筆者通過網上找了一些帶alpha通道的png圖片,果真被標識為洋紅色了。不過奇怪的是,兩個一樣的圖片,為什么顯示成正方形的時候,并沒有被標識為像素不對齊呢?
筆者嘗試修改左上角的頭像為長方形,不過并沒有用,還是顯示為黃色而非洋紅色。而且,這設置圖片的代碼是一樣一樣的,結果還是沒有變化修改成洋紅色,這個問題筆者暫時找不到原因。
希望大家知道原因的,可以告知一聲,謝謝!
在優化前,我們監測FPS如下:
Color Misaligned Images
右邊一列是FPS值的變化,我們是在滾動時的FPS,說明不做優化處理,對于滾動的流暢性影響是比較大的。
在優化前的代碼是:
NSString *path = nil; if ([model.headImghasSuffix:@".png"]) { ? ? path = model.headImg; } else { ? ? path = [[NSBundle mainBundle]pathForResource:model.headImgofType:nil]; } UIImage *image = [UIImageimageNamed:path]; self.headImageView.image = image;
對于UICollectionViewCell中顯示的圖片優化前是這樣的:
NSString *imgName = self.model.imgs[indexPath.row]; NSString *path = nil; if ([imgNamehasSuffix:@".png"]) { ? ? path = imgName; } else { ? ? path = [[NSBundle mainBundle]pathForResource:imgNameofType:nil]; } UIImage *image = [UIImageimageNamed:path]; imgView.image = image;
優化后
在優化后,我們通過真機監測FPS在滾動時的變化,可以看到是比較穩定地處于60左右,說明優化的效果是比較明顯的:
Color Misaligned Images
下面我們采用等比例的方式來生成新的圖片并緩存起來,看到優化后的效果:
Color Misaligned Images
我們發現洋紅色沒有了,黃色也沒有了。說明我們已經解決掉這個問題了。
等比例縮放
那么我們采用等比例縮放圖片的代碼如下(給UIImage添加了一個擴展方法):
// 等比縮放 - (UIImage *)hyb_cropEqualScaleImageToSize:(CGSize)size { ? ? CGFloat scale = ?[UIScreen mainScreen].scale; ? ? ?// 這一行至關重要 ? // 不要直接使用UIGraphicsBeginImageContext(size);方法 ? // 因為控件的frame與像素是有倍數關系的 ? // [email protected] @[email protected] ,因此我們必須要指定scale,否則黃色去不了 ? // 因為在5以上,scale為2,6plus scale為3,所生成的圖是要合蘋果的 ? // 規格才能正常 ? UIGraphicsBeginImageContextWithOptions(size, NO, scale); ? ? ?CGSize aspectFitSize = CGSizeZero; ? if (self.size.width != 0 && self.size.height != 0) { ? ? CGFloat rateWidth = size.width / self.size.width; ? ? CGFloat rateHeight = size.height / self.size.height; ? ? ? ? ?CGFloat rate = MIN(rateHeight, rateWidth); ? ? aspectFitSize = CGSizeMake(self.size.width* rate, self.size.height* rate); ? } ? ? ?[selfdrawInRect:CGRectMake(0, 0, aspectFitSize.width, aspectFitSize.height)]; ? UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); ? UIGraphicsEndImageContext(); ? ? ?return image; }
直接縮放至指定大小
下圖是不按等比例來縮放,而是直接生成指定大小的圖,優化后的效果圖如下:
Color Misaligned Images
而我們生成指定大小的圖的代碼如下:
// 非等比縮放,生成的圖片可能會被拉伸 - (UIImage *)hyb_cropEqualScaleImageToSize:(CGSize)size { ? CGFloat scale = ?[UIScreen mainScreen].scale; ? ? UIGraphicsBeginImageContextWithOptions(size, NO, scale); ? ? ?[selfdrawInRect:CGRectMake(0, 0, size.width, size.height)]; ? UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); ? UIGraphicsEndImageContext(); ? ? ?return image; }
配置用戶頭像
配置用戶頭像處的代碼就修改成如下,換成在子線程里處理圖片裁剪,生成與headImageView正好合適的圖片的大小,這樣就不會出現圖片需要UIImageView壓縮的問題,性能自然得到提升:
// 優化后 dispatch_async(dispatch_get_global_queue(0, 0), ^{ ? NSString *path = nil; ? if ([model.headImghasSuffix:@".png"]) { ? ? path = model.headImg; ? } else { ? path = [[NSBundle mainBundle]pathForResource:model.headImgofType:nil]; ? } ? UIImage *image = [[UIImageimageNamed:path]hyb_cropEqualScaleImageToSize:self.headImageView.frame.size]; ? dispatch_async(dispatch_get_main_queue(), ^{ ? ? self.headImageView.image = image; ? }); });
配置CollectionViewCell
在優化后,我們在配置UICollectionView中的圖片時,代碼是這樣的:
NSString *imgName = self.model.imgs[indexPath.row]; if ([self.model.cacheImagesobjectForKey:imgName]) { ? imgView.image = [self.model.cacheImagesobjectForKey:imgName]; } else { ? ? ?dispatch_async(dispatch_get_global_queue(0, 0), ^{ ? ? ? ? ?NSString *path = nil; ? ? if ([imgNamehasSuffix:@".png"]) { ? ? ? path = imgName; ? ? } else { ? ? ? path = [[NSBundle mainBundle]pathForResource:imgNameofType:nil]; ? ? } ? ? ? UIImage *image = [[UIImageimageNamed:path]hyb_cropEqualScaleImageToSize:imgView.frame.size]; ? ? dispatch_async(dispatch_get_main_queue(), ^{ ? ? ? imgView.image = image; ? ? ? if (image) { ? ? ? ? [self.model.cacheImagessetObject:imageforKey:imgName]; ? ? ? } ? ? }); ? }); }
我們首先是放在異步線程去去處圖片的裁剪生成新的合適的圖片,然后再回到主線程來更新顯示圖片。這么處理就不會阻塞主線程了,流暢度是否好多了~
注意事項
當我們設置不透明度為NO時,表示透明,這時候通過Color Blended Layers發現圖片變成紅色了,那是因為透明原因,將第二個參數設置成YES就可以解決了:
UIGraphicsBeginImageContextWithOptions(size, NO, scale);
最后
對于圖片優化問題,個人覺得應該要根據情況而定,如果是在列表中需要滾動的,希望滾動可以很流暢的,才需要這么去優化它。對于那些不是滾動的界面,沒有必須非得去優化它。
請大家多多反饋意見,說說自己的想法,在遇到問題能夠將解決方案告知筆者,共同進步!
眼前還有三個月就要去深圳謀發展了,寫下本篇,就當是提前準備準備吧!
總結
優化UIImageView顯示出現圖片大小與控件大小不一致時,可以采用重新生成新的正好合適的圖片上這種方式。
同樣像UIButton這樣也需要顯示圖片時,也可以采用UIImageView這種方式
對新生成的圖片,最好緩存起來
源代碼
筆者提供了小Demo的,這個小demo也是如何在cell中嵌入collectionview的使用。
GITHUB下載地址: CoderJackyHuang’s PerformanceDemo
參考
UIKit性能調優實戰講解