更正
經過代碼以及instruments工具測試,以下更正
官方對離屏渲染產生性能問題也進行了優化:
iOS 9.0 之前UIimageView跟UIButton設置圓角都會觸發離屏渲染。
iOS 9.0 之后UIButton設置圓角會觸發離屏渲染,而UIImageView里png圖片設置圓角不會觸發離屏渲染了,如果設置其他陰影效果之類的還是會觸發離屏渲染的。
第一種方法:通過設置layer的屬性
代碼:
UIImageView *imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"TestImage"]];
// 只需設置layer層的兩個屬性
// 設置圓角
imageView.layer.cornerRadius = 50;
// 將多余的部分切掉
imageView.layer.masksToBounds = YES;
[self.view addSubview:imageView];
這個方法里maskToBounds會觸發離屏渲染,GPU在當前屏幕緩沖區外新開辟了一個渲染緩沖區進行工作,也就是離屏渲染,這會給我們帶來額外的性能損耗,如果這樣的圓角操作達到一定數量,會觸發緩沖區的頻繁合并和上下文的頻繁切換,性能的代價會宏觀的表現在用戶體驗上<掉幀>。
第二種方法:使用貝塞爾曲線UIBezierPath和Core Graphics框架畫出一個圓角
代碼:
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)];
imageView.image = [UIImage imageNamed:@"TestImage.jpg"];
// 開始對imageView進行畫圖
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 0.0);
// 使用貝塞爾曲線畫出一個圓形圖
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds cornerRadius:imageView.frame.size.width] addClip];
[imageView drawRect:imageView.bounds];
imageView.image = UIGraphicsGetImageFromCurrentImageContext();
// 結束畫圖
UIGraphicsEndImageContext();
[self.view addSubview:imageView];
- UIGraphicsBeginImageContextWithOption(CGSize size, BOOL opaque, CGFloat scale)各參數的含義:
- size ---新創建的文圖上下文大小
- opaque --- 透明開關,如果圖形完全不用透明,設置為YES以優化位圖的存儲。
- scale --- 縮放因子。雖然這里可以用[UIScreen mainScreen].scale來獲取,但實際上設為0后,系統會自動設置正確的比例
第三種方法: 使用Core Graphics框架畫出一個圓角
代碼:
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 200, 100, 100)];
imageView.image = [UIImage imageNamed:@"TestImage.jpg"];
// 開始對imageView進行畫圖
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 0.0);
// 獲取圖形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 設置一個范圍
CGRect rect = CGRectMake(0, 0, imageView.frame.size.width, imageView.frame.size.height);
// 根據一個rect創建一個橢圓
CGContextAddEllipseInRect(ctx, rect);
// 裁剪
CGContextClip(ctx);
// 講原照片畫到圖形上下文
[imageView.image drawInRect:rect];
// 從上下文上獲取裁剪后的照片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
// 關閉上下文
UIGraphicsEndImageContext();
imageView.image = image;
[self.view addSubview:imageView];
第四種方法: 使用CAShapeLayer和UIBezierPath設置圓角
代碼:
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 200, 100, 100)];
imageView.image = [UIImage imageNamed:@"TestImage.jpg"];
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];
指定需要的角成為圓角(第四種方法的延伸)
方法:
+ (UIBezierPath *)bezierPathWithRoundedRect:(CGRect)rect
byRoundingCorners:(UIRectCorner)corners
cornerRadii:(CGSize)cornerRadii;
corners參數指定了要成為圓角的角, 枚舉類型如下:
typedef NS_OPTIONS(NSUInteger, UIRectCorner) {
UIRectCornerTopLeft = 1 << 0,
UIRectCornerTopRight = 1 << 1,
UIRectCornerBottomLeft = 1 << 2,
UIRectCornerBottomRight = 1 << 3,
UIRectCornerAllCorners = ~0UL
};
實現代碼:
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 200, 200, 200)];
imageView.image = [UIImage imageNamed:@"TestImage.jpg"];
// 繪制圓角 需設置的圓角 使用"|"來組合
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:imageView.bounds byRoundingCorners:UIRectCornerTopLeft |
UIRectCornerBottomRight cornerRadii:CGSizeMake(30, 30)];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
// 設置大小
maskLayer.frame = imageView.bounds;
// 設置圖形樣子
maskLayer.path = maskPath.CGPath;
imageView.layer.mask = maskLayer;
[self.view addSubview:imageView];
效果圖:
image.png
然而第四種方法并不可取,存在離屏渲染。
進過實際測試之后,以及哪種方法最為可取,具體可以參考iOS圓角四種方法的對比以及性能檢測(一定要看哦)