iOS圖片設置圓角性能問題

轉載:html

http://www.jianshu.com/p/34189f62bfd8ios

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

 

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

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

 注意:png圖片UIImageView處理圓角是不會產生離屏渲染的。(ios9.0以後不會離屏渲染,ios9.0以前仍是會離屏渲染)。

全部若是要高性能的設置圓角就須要找另外的方法了。下面是我找到的一些方法並寫了一個例子。緩存

設置圓角的方法less

  • 直接使用setCornerRadius  這種就是最經常使用的,也是最耗性能的。異步

  • 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經常改變的話,它就會一直不停的渲染及刪除緩存從新
    建立緩存,因此這種狀況下建議不要使用光柵化,這樣也是比較損耗性能的。
    

      

  • 直接覆蓋一張中間爲圓形透明的圖片(推薦使用)測試

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

      

  • 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消耗會高,內存佔用也會暴增,並且後臺線程繪製會比在主線程繪製佔用更多的內存,不知道怎麼解決?求大神指教! ui

  • 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
      開啓後會把那些須要離屏渲染的圖層高亮成黃色,這就意味着黃色圖層可能存在性能問題。

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

    用Instruments測試得

    • 第一種方法,UIImageView和UIButton都高亮爲黃色。

    • 第二種方法,UIImageView和UIButton都高亮爲綠色

    • 第三種方法,無任何高亮,說明沒離屏渲染。
      這種圓片覆蓋的方法通常只用在底色爲純色的時候,若是圓角圖片的父View是張圖片的時候就沒辦法了,並且底色若是是多種顏色的話那要作多張不一樣顏色的圓片覆蓋。(能夠用代碼取底色的顏色值給圓片着色)

    • 第四種方法無任何高亮,說明沒離屏渲染(可是CPU消耗和內存佔用會很大)

    • 第五種方法無任何高亮,說明沒離屏渲染,並且內存佔用也不大。(暫時感受是最優方法)


    問題回覆:

    • 有回覆提到還有一種mask方法。
      這種方法比第一種方法其實更卡頓。一次mask發生了兩次離屏渲染和一次主屏渲染。 具體能夠參考當心別讓圓角成了你列表的幀數殺手

    • @nerozhao說第四種比第一種更卡。

      我剛在demo里加了個例子測試了一下,第一種能明顯的感受到卡頓,第四種仍是挺順暢 的,有興趣的能夠本身試試看。第四種是解決了離屏渲染GPU的問題。

    能夠用Instruments的 GPU Driver進行測試:

    • Renderer Utilization
      若是這個值超過了~50%,就意味着你的動畫可能對幀率有所限制,極可能由於離屏渲染或者是重繪致使的過分混合。
    • Tiler Utilization
      若是這個值超過了~50%,就意味着你的動畫可能限制於幾何結構方面,也就是在屏幕上有太多的圖層佔用了。

    Instruments

    圖上面一部分是第一種方法的數據,下面一部分是第四種方法的數據。
    第一種方法的Renderer Utilization 和 Tiler Utilization 基本在90%左右。幀率在20左右。
    第四種方法的Renderer Utilization 和 Tiler Utilization 基本在20%左右。幀率接近60。
    幀率越接近60滑動越順暢。

    可是通過跟@nerozhao的討論發現第四種Core Graphics繪製圓角會有大量的內存佔用, 並且每次繪製的時候CUP消耗會很大。 因爲@nerozhao使用了UITableView進行測試,由於UITableView滾動的時候是一直在 複用的,UIImageView會重複繪製,因此會一直消耗CUP,而後你就能看的明顯的卡頓。 @nerozhao在UITableView裏圖片的繪製在後臺線程進行繪製,解決了卡頓問題,可是 因爲是在後臺線程的異步繪製因此在滾動的時候會看到圖片先是正方形而後再變成圓形。 而我使用的是UIScrollerView進行的測試,只有第一次繪製的時候會佔用CUP資源, 因此滑動的時候仍是挺流暢的,可是內存消耗仍是很大。若是是主線程繪製的話會阻塞一 點時間的主線程,然後臺線程繪製的話內存消耗會更大,特別容易崩潰。

    因此第四種方法當圖片特別多的時候很容易Received memory warning致使崩潰

相關文章
相關標籤/搜索