iOS 離屏渲染的研究(三)-------圖片設置圓角性能問題

demo下載ios

通常咱們在iOS開發的過程當中設置圓角都是以下這樣設置的。
git

avatarImageView.clipsToBounds = YES;
 [avatarImageView.layer setCornerRadius:50];

 這樣設置會觸發離屏渲染,比較消耗性能。好比當一個頁面上有十幾頭像這樣設置了圓角
 會明顯感受到卡頓。

 注意:png圖片UIImageView處理圓角是不會產生離屏渲染的。(ios9.0以後不會離屏渲染,ios9.0以前仍是會離屏渲染)。
全部若是要高性能的設置圓角就須要找另外的方法了。下面是我找到的一些方法並寫了一個例子。



設置圓角的方法
github

(1)直接使用setCornerRadius緩存

這種就是最經常使用的,也是最耗性能的。
(2) setCornerRadius設置圓角以後,shouldRasterize=YES光柵化

avatarImageView.clipsToBounds = YES;
[avatarImageView.layer setCornerRadius:50];
avatarImageView.layer.shouldRasterize = YES;
avatarImageViewUrl.layer.rasterizationScale=[UIScreen mainScreen].scale;  //UIImageView不加這句會產生一點模糊

shouldRasterize=YES設置光柵化,可使離屏渲染的結果緩存到內存中存爲位圖,
使用的時候直接使用緩存,節省了一直離屏渲染損耗的性能。

可是若是layer及sublayers經常改變的話,它就會一直不停的渲染及刪除緩存從新
建立緩存,因此這種狀況下建議不要使用光柵化,這樣也是比較損耗性能的。
(3) 直接覆蓋一張中間爲圓形透明的圖片(推薦使用)

這種方法就是多加了一張透明的圖片,GPU計算多層的混合渲染blending也是會消耗
一點性能的,但比第一種方法仍是好上不少的。
(4) UIImage drawInRect繪製圓角

這種方式GPU損耗低內存佔用大,並且UIButton上不知道怎麼繪製,能夠用
UIimageView添加個點擊手勢當作UIButton使用。

UIGraphicsBeginImageContextWithOptions(avatarImageView.bounds.size, NO, [UIScreen mainScreen].scale);
[[UIBezierPath bezierPathWithRoundedRect:avatarImageView.bounds
                              cornerRadius:50] addClip];
[image drawInRect:avatarImageView.bounds];
avatarImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

這段方法能夠寫在SDWebImage的completed回調裏,在主線程異步繪製。
也能夠封裝到UIImageView裏,寫了個DSRoundImageView。後臺線程異步繪製,不會阻塞主線程。
問題:這種方法圖片不少的話CUP消耗會高,內存佔用也會暴增,並且後臺線程繪製會比在主線程繪製佔用更多的內存,不知道怎麼解決?求大神指教!

(5)SDWebImage處理圖片時Core Graphics繪製圓角
異步

//UIImage繪製爲圓角
  int w = imageSize.width;
  int h = imageSize.height;
  int radius = imageSize.width/2;

  UIImage *img = image;
  CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
  CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
  CGRect rect = CGRectMake(0, 0, w, h);

  CGContextBeginPath(context);
  addRoundedRectToPath(context, rect, radius, radius);
  CGContextClosePath(context);
  CGContextClip(context);
  CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
  CGImageRef imageMasked = CGBitmapContextCreateImage(context);
  img = [UIImage imageWithCGImage:imageMasked];

  CGContextRelease(context);
  CGColorSpaceRelease(colorSpace);
  CGImageRelease(imageMasked);

以上代碼我寫成了UIImage的類別:UIImage+DSRoundImage.h
並在SDWebImage庫裏處理image的時候使用類別方法繪製圓角並緩存。性能


使用Instruments的Core Animation查看性能測試

  • Color Offscreen-Rendered Yellow
    開啓後會把那些須要離屏渲染的圖層高亮成黃色,這就意味着黃色圖層可能存在性能問題。ui

  • Color Hits Green and Misses Red
    若是shouldRasterize被設置成YES,對應的渲染結果會被緩存,若是圖層是綠色,就表示這些緩存被複用;若是是紅色就表示緩存會被重複建立,這就表示該處存在性能問題了。spa

用Instruments測試線程

第(1)種方法,UIImageView和UIButton都高亮爲黃色。

第(2)種方法,UIImageView和UIButton都高亮爲綠色
第(3)種方法,無任何高亮,說明沒離屏渲染。
這種圓片覆蓋的方法通常只用在底色爲純色的時候,若是圓角圖片的父View是張圖片的時候就沒辦法了,並且底色若是是多種顏色的話那要作多張不一樣顏色的圓片覆蓋。(能夠用代碼取底色的顏色值給圓片着色)
第(4)種方法無任何高亮,說明沒離屏渲染(可是CPU消耗和內存佔用會很大)
第(5)種方法無任何高亮,說明沒離屏渲染,並且內存佔用也不大。(暫時感受是最優方法)


 參考:http://www.jianshu.com/p/34189f62bfd8
相關文章
相關標籤/搜索