iOS圖片設置圓角性能優(yōu)化

對圖片進行圓角處理會相比于直角,它更加柔和優(yōu)美,是一種很常見的視圖效果,在APP中常用于對用戶頭像的美化,但是設置不當就會讓你的APP性能下降,導致掉幀,影響用戶體驗
首先介紹一下常用的切圓角的幾種常見方式

第一種方法:通過設置layer的屬性

UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)]; //只需要設置layer層的兩個屬性  
//設置圓角    
 imageView.layer.cornerRadius = imageView.frame.size.width / 2; 
//將多余的部分切掉
 imageView.layer.masksToBounds = YES;
 [self.view addSubview:imageView];

但是這種方式切圓角的很大一個弊端就是影響性能,對于圖片較少的情況下還不是很明顯,不會太影響幀數(shù),但是圖片多的時候就會嚴重影響幀數(shù)(視圖和圓角的大小對幀率并沒有什么卵影響,數(shù)量才是傷害的核心輸出),大概圓角的數(shù)量在30-40左右的時候,界面就會卡出翔的節(jié)奏,所以開發(fā)中一般不會用這個方法.
一開始我以為導致幀數(shù)下降的原因是imageView.layer.cornerRadius 這個方法造成的,后來才發(fā)現(xiàn)罪魁禍首是imageView.layer.masksToBounds ,這玩意會導致離屏渲染,
離屏渲染我并沒有深入的去了解,在網(wǎng)上找資料大體的了解下

渲染機制是GPU在當前屏幕緩沖區(qū)外新開辟一個渲染緩沖區(qū)進行工作,也就是離屏渲染,這會給我們帶來額外的性能損耗,如果這樣的圓角操作達到一定數(shù)量,會觸發(fā)緩沖區(qū)的頻繁合并和上下文的的頻繁切換,性能的代價會宏觀地表現(xiàn)在用戶體驗上----掉幀

但是ios9之后蘋果對離屏渲染做了優(yōu)化
1.iOS 9.0 之前UIimageView跟UIButton設置圓角都會觸發(fā)離屏渲染
2.iOS 9.0 之后UIButton設置圓角會觸發(fā)離屏渲染,而UIImageView里png圖片設置圓角不會觸發(fā)離屏渲染了,如果設置其他陰影效果之類的還是會觸發(fā)離屏渲染的。
這可能是蘋果也意識到離屏渲染會產生性能問題,所以能不產生離屏渲染的地方蘋果也就不用離屏渲染了。
對第一種方法的總結
1.如果圖片數(shù)量很少,能夠只用 cornerRadius 解決問題,就不用優(yōu)化。
2.如果必須設置 masksToBounds,而且只是設置UIImageView的圓角,那么久不用考慮離屏渲染,如果設置其他的空間,那么就要在空間設置圓角過多的情況下舍棄這一種方法

第二種方法:使用貝塞爾曲線UIBezierPath和Core Graphics框架畫出一個圓角

UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)]; 
imageView.image = [UIImage imageNamed:@"1"]; 
//開始對imageView進行畫圖 UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0); 
//使用貝塞爾曲線畫出一個圓形圖 
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds cornerRadius:imageView.frame.size.width] addClip];
 [imageView drawRect:imageView.bounds];
 imageView.image = UIGraphicsGetImageFromCurrentImageContext(); 
//結束畫圖 
UIGraphicsEndImageContext(); [self.view addSubview:imageView];

第三種方法:使用CAShapeLayer和UIBezierPath設置圓角

#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad { [super viewDidLoad]; 
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)]; imageView.image = [UIImage imageNamed:@"1"]; 
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:imageView.bounds.size];
 CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init]; 
//設置大小 
maskLayer.frame = imageView.bounds; 
//設置圖形樣子 
maskLayer.path = maskPath.CGPath;
 imageView.layer.mask = maskLayer; 
[self.view addSubview:imageView];}

1.首先是CAShapeLayer
1.1CAShapeLayer繼承于CALayer,可以使用CALayer的所有屬性值;
1.2CAShapeLayer需要貝塞爾曲線配合使用才有意義(也就是說才有效果)
1.3使用CAShapeLayer(屬于CoreAnimation)與貝塞爾曲線可以實現(xiàn)不在view的drawRect(繼承于CoreGraphics走的是CPU,消耗的性能較大)方法中畫出一些想要的圖形
1.4CAShapeLayer動畫渲染直接提交到手機的GPU當中,相較于view的drawRect方法使用CPU渲染而言,其效率極高,能大大優(yōu)化內存使用情況
總的來說就是用CAShapeLayer的內存消耗少,渲染速度快,建議使用第三種

框架ZYCornerRadius

另外在給大家介紹一個第三方框架,雖然star不多,但是感覺挺使用,個人使用的不是太多,因為平時工作中大量的圖片切圓角并沒有遇到,
地址:https://github.com/liuzhiyi1992/ZYCornerRadius
我簡單的了解了下,作者用了兩種途徑去實現(xiàn),一個是uiimageView的分類,另外一個是子類實現(xiàn),而且用到了runtime運行時的知識,(給分類中增加私有屬性),總體會大大降低了設置圓角是產生的內存占用高和幀數(shù)低的問題,而且還支持多種帶邊框的圓角,這里就不在多贅述了,大家有需要的可以去github去克隆下來研究研究

最后總結

1.對于圓角少的情況下,而且是ios9以上,設置圖片可以不用考慮離屏渲染,數(shù)量少的陰影和其他控件的圓角設置也影響不大
2.數(shù)量多的情況,而且ios9以下的情況切忌使用cornerRadius,maskToBounds來設置,掉幀太嚴重,盡量使用貝塞爾曲線和Core Graphics框架或者CAShapeLayer來去實現(xiàn),或者用第三方框架

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容