一般我們在iOS開發(fā)的過程中設(shè)置圓角都是如下這樣設(shè)置的社裆。
avatarImageView.clipsToBounds = YES;
[avatarImageView.layer setCornerRadius:50];
這樣設(shè)置會觸發(fā)離屏渲染登馒,比較消耗性能点寥。比如當(dāng)一個頁面上有十幾頭像這樣設(shè)置了圓角
會明顯感覺到卡頓拌喉。
注意:png圖片UIImageView處理圓角是不會產(chǎn)生離屏渲染的。(ios9.0之后不會離屏渲染押框,ios9.0之前還是會離屏渲染)岔绸。
所有如果要高性能的設(shè)置圓角就需要找另外的方法了。下面是我找到的一些方法并寫了一個例子橡伞。
設(shè)置圓角的方法
直接使用setCornerRadius
這種就是最常用的盒揉,也是最耗性能的。-
setCornerRadius設(shè)置圓角之后骑歹,shouldRasterize=YES光柵化
avatarImageView.clipsToBounds = YES; [avatarImageView.layer setCornerRadius:50]; avatarImageView.layer.shouldRasterize = YES; avatarImageViewUrl.layer.rasterizationScale=[UIScreen mainScreen].scale; //UIImageView不加這句會產(chǎn)生一點模糊 shouldRasterize=YES設(shè)置光柵化预烙,可以使離屏渲染的結(jié)果緩存到內(nèi)存中存為位圖, 使用的時候直接使用緩存道媚,節(jié)省了一直離屏渲染損耗的性能扁掸。 但是如果layer及sublayers常常改變的話,它就會一直不停的渲染及刪除緩存重新 創(chuàng)建緩存最域,所以這種情況下建議不要使用光柵化谴分,這樣也是比較損耗性能的。
直接覆蓋一張中間為圓形透明的圖片(推薦使用)
這種方法就是多加了一張透明的圖片镀脂,GPU計算多層的混合渲染blending也是會消耗
一點性能的牺蹄,但比第一種方法還是好上很多的。-
UIImage drawInRect繪制圓角
這種方式GPU損耗低內(nèi)存占用大薄翅,而且UIButton上不知道怎么繪制沙兰,可以用
UIimageView添加個點擊手勢當(dāng)做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回調(diào)里,在主線程異步繪制鼎天。 也可以封裝到UIImageView里舀奶,寫了個DSRoundImageView。后臺線程異步繪制斋射,不會阻塞主線程育勺。
問題:這種方法圖片很多的話CUP消耗會高,內(nèi)存占用也會暴增罗岖,而且后臺線程繪制會比在主線程繪制占用更多的內(nèi)存涧至,不知道怎么解決?求大神指教桑包!
-
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被設(shè)置成YES蓖康,對應(yīng)的渲染結(jié)果會被緩存,如果圖層是綠色垒手,就表示這些緩存被復(fù)用;如果是紅色就表示緩存會被重復(fù)創(chuàng)建倒信,這就表示該處存在性能問題了科贬。
用Instruments測試得
第一種方法,UIImageView和UIButton都高亮為黃色鳖悠。
第二種方法榜掌,UIImageView和UIButton都高亮為綠色
第三種方法,無任何高亮乘综,說明沒離屏渲染憎账。
這種圓片覆蓋的方法一般只用在底色為純色的時候,如果圓角圖片的父View是張圖片的時候就沒辦法了卡辰,而且底色如果是多種顏色的話那要做多張不同顏色的圓片覆蓋胞皱。(可以用代碼取底色的顏色值給圓片著色)第四種方法無任何高亮,說明沒離屏渲染(但是CPU消耗和內(nèi)存占用會很大)
第五種方法無任何高亮九妈,說明沒離屏渲染反砌,而且內(nèi)存占用也不大。(暫時感覺是最優(yōu)方法)
問題回復(fù):
有回復(fù)提到還有一種mask方法萌朱。
這種方法比第一種方法其實更卡頓宴树。一次mask發(fā)生了兩次離屏渲染和一次主屏渲染。 具體可以參考小心別讓圓角成了你列表的幀數(shù)殺手-
@nerozhao說第四種比第一種更卡晶疼。
我剛在demo里加了個例子測試了一下酒贬,第一種能明顯的感覺到卡頓又憨,第四種還是挺順暢 的,有興趣的可以自己試試看锭吨。第四種是解決了離屏渲染GPU的問題蠢莺。
可以用Instruments的 GPU Driver進(jìn)行測試:
- Renderer Utilization
如果這個值超過了~50%,就意味著你的動畫可能對幀率有所限制耐齐,很可能因為離屏渲染或者是重繪導(dǎo)致的過度混合浪秘。 - Tiler Utilization
如果這個值超過了~50%,就意味著你的動畫可能限制于幾何結(jié)構(gòu)方面埠况,也就是在屏幕上有太多的圖層占用了耸携。
圖上面一部分是第一種方法的數(shù)據(jù),下面一部分是第四種方法的數(shù)據(jù)辕翰。
第一種方法的Renderer Utilization 和 Tiler Utilization 基本在90%左右夺衍。幀率在20左右。
第四種方法的Renderer Utilization 和 Tiler Utilization 基本在20%左右喜命。幀率接近60沟沙。
幀率越接近60滑動越順暢。
但是經(jīng)過跟@nerozhao的討論發(fā)現(xiàn)第四種Core Graphics繪制圓角會有大量的內(nèi)存占用壁榕,
而且每次繪制的時候CUP消耗會很大矛紫。
由于@nerozhao使用了UITableView進(jìn)行測試,因為UITableView滾動的時候是一直在
復(fù)用的牌里,UIImageView會重復(fù)繪制颊咬,所以會一直消耗CUP,然后你就能看的明顯的卡頓牡辽。
@nerozhao在UITableView里圖片的繪制在后臺線程進(jìn)行繪制喳篇,解決了卡頓問題,但是
由于是在后臺線程的異步繪制所以在滾動的時候會看到圖片先是正方形然后再變成圓形态辛。
而我使用的是UIScrollerView進(jìn)行的測試麸澜,只有第一次繪制的時候會占用CUP資源,
所以滑動的時候還是挺流暢的奏黑,但是內(nèi)存消耗還是很大炊邦。如果是主線程繪制的話會阻塞一
點時間的主線程,而后臺線程繪制的話內(nèi)存消耗會更大攀涵,特別容易崩潰铣耘。
所以第四種方法當(dāng)圖片特別多的時候很容易Received memory warning導(dǎo)致崩潰
解決問題參考文章
- UIImage drawInRect繪制圓角內(nèi)存暴增問題
- github 繪制圓角源碼參考
最后
關(guān)于研究過程及各種設(shè)置圓角方法的例子測試對比 github源碼
如果我的文章對你有幫助歡迎github Star
如果你有什么問題或者想交流的可以聯(lián)系我。QQ:398411773