iOS - 視圖圓角

一、疊加圖片

用一個四角爲和下一層視圖顏色一樣的弧度角,當下一層爲透明時,無法使用。

二、CALayer的cornerRadius

cornerRadius屬性影響layer顯示的background顏色和前景框border,對layer的contents不起作用。故一個imgView(類型爲UIImageView)的image不爲空,設置imgView.layer的cornerRadius,是看不出顯示圓角效果的,因爲image是imgView.layer的contents部分。
這種情況下將layer的masksToBounds屬性設置爲YES,可以正確的繪製出圓角效果。但是cornerRadius>0,masksToBounds=YES,會觸發GPU的離屏渲染,當一個屏幕上有多處觸發離屏渲染,會影響性能。通過勾選Instruments->Core Animation->Color Offscreen-Rendered Yellow,可以看到屏幕上觸發離屏渲染的會被渲染成黃色。離屏渲染的代價昂貴,蘋果也意識到會產生性能問題,所以iOS9以後的系統裏能不產生離屏渲染的地方也就不用離屏渲染了。比如對UIImageView裏png圖片設置圓角不會觸發離屏渲染。

1.對contents爲空的視圖設置圓角

view.backgroundColor = [UIColor redColor];
view.layer.cornerRadius = 25;
//UILabel設置backgroundColor的行爲被更改,不再是設定layer的背景色而是爲contents設置背景色
label.layer.backgroundColor = aColor
label.layer.cornerRadius = 5

2.對contents不爲空的視圖設置圓角

imageView.image = [UIImage imageNamed:@"img"];
imageView.image.layer.cornerRadius = 5;
imageView.image.layer.masksToBounds = YES;

三、設置CALayer的mask(蒙板)

通過設置view.layer的mask屬性,可以將另一個layer蓋在view上,也可以設置圓角,但是mask同樣會觸發離屏渲染。
有兩種方式來生成遮罩,一是通過圖片生成,圖片的透明度影響着view繪製的透明度,圖片遮罩透明度爲1的部分view被繪製成的透明度爲0,相反圖片遮罩透明度爲0的部分view被繪製成的透明度爲1。二是通過貝塞爾曲線生成,view中曲線描述的形狀部分會被繪製出來。

// 通過圖片生成遮罩,
UIImage *maskImage = [UIImage imageNamed:@"someimg"];
CALayer *mask = [CALayer new];
mask.frame = CGRectMake(0, 0, maskImage.size.width, maskImage.size.height);
mask.contents = (__bridge id _Nullable)(maskImage.CGImage);
view.layer.mask = mask;
//通過貝塞爾曲線生成
CAShapeLayer *mask = [CAShapeLayer new];
mask.path = [UIBezierPath bezierPathWithOvalInRect:view.bounds].CGPath;
view.layer.mask = mask;

四、通過Core Graphics重新繪製帶圓角的視圖

通過CPU重新繪製一份帶圓角的視圖來實現圓角效果,會大大增加CPU的負擔,而且相當於多了一份視圖拷貝會增加內存開銷。但是就顯示性能而言,由於沒有觸發離屏渲染,所以能保持較高幀率。下例是繪製一個圓形圖片,繪製其它UIView並無本質區別。重新繪製的過程可以交由後臺線程來處理。

@implementation UIImage (CircleImage)
- (UIImage *)drawCircleImage {
CGFloat side = MIN(self.size.width, self.size.height);
UIGraphicsBeginImageContextWithOptions(CGSizeMake(side, side), false, [UIScreen mainScreen].scale);
CGContextAddPath(UIGraphicsGetCurrentContext(),
[UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, side, side)].CGPath);
CGContextClip(UIGraphicsGetCurrentContext());
CGFloat marginX = -(self.size.width - side) / 2.f;
CGFloat marginY = -(self.size.height - side) / 2.f;
[self drawInRect:CGRectMake(marginX, marginY, self.size.width, self.size.height)];
CGContextDrawPath(UIGraphicsGetCurrentContext(), kCGPathFillStroke);
UIImage *output = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return output;
}
@end
//在需要圓角時調用如下
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIImage *img = [[UIImage imageNamed:@"image.png"] drawCircleImage];
dispatch_async(dispatch_get_main_queue(), ^{
view.image = img;
});
});
發佈了116 篇原創文章 · 獲贊 4 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章