设置圆角触发离屏渲染?
通常我们会认为只要设置了圆角,就会触发离屏渲染,其实不然,并非所有的圆角都会触发离屏渲染。
//按钮有设置背景图片
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(0, 0, 120, 120);
[btn setImage:[UIImage imageNamed:@"btnback"] forState:UIControlStateNormal];
btn.layer.cornerRadius = 60;
btn.clipsToBounds = YES;
btn.center = self.view.center;
[self.view addSubview:btn];没有设置layer.masksToBounds或者clipsToBounds,其默认值为NO
这里我们运行后打开模拟器的离屏渲染颜色标记:
设置了layer.masksToBounds会发现触发了离屏渲染:
离屏渲染的原因
- 首先我们了解下渲染流程:
由上渲染流程图我们知道App应用需要进行额外的渲染和合并,此时需要用到offscreenn Buffer组合放到FrameBuffer,最终显示到屏幕。
离屏渲染是需要开辟额外的储存空间,如果使用大量的离屏渲染,性能方面会大大的降低。因此应尽可能的减少离屏渲染。
- 既然如此,为什么我们仍需要使用离屏渲染呢?
1、在实现一些特殊效果的时候,需要使用额外的offscreen Buffer 保存中间状态,不得不使用离渲染。如:系统自动触发、圆角、阴影。
2、效率优势,效果会多次出现在屏幕上,我们可以提取渲染好,保存在offscreenBuffer,从而达到复用的目的。
关于光栅化
shouldRasterize:设置光栅化;CALayer会被光栅化为bitmap,layer的阴影等效果也会被保存到bitmap中,使用时直接读取
btn.imageView.layer.shouldRasterize = YES;光栅化的使用建议:
- 如果layer不能被复用,则没有必要打开光栅化;
- 如果layer不是静态的,需要被频繁修改,比如处于动画之中,那么开启离屏渲染而反而影响效率了;
- 离屏渲染缓存内容有时间限制,缓存100ms内容,如果没有被使用,那么它会丢弃,无法进行复用了;
- 离屏渲染内存空间有限。超过2.5倍屏幕像素大小的话,便会失效,且无法进行复用了;
圆⻆触发的离屏渲染offscreenRendering
绘制涂层背景时使用的半径,可设置动画。
设置layer.cornerRadius只会设置backgroundColor和border的圆角。不会设置内容的圆角,除非同时设置了layer.masksToBounds为True(对应View中的clipsTopBounds属性)。
btn.layer.masksToBounds = YES;iOS上的圆⻆处理⼿段参考⽅案iOS上的圆⻆处理⼿段参考⽅案
- 方案一、
// 设置圆角
btn.imageView.layer.cornerRadius = 60.0;
// 设置裁剪
btn.imageView.clipsToBounds = YES;- 方案二、
- (UIImage *)rundedCornerImageWithConnerRadius:(CGFloat)cornerRadius{
CGFloat width = self.frame.size.width;
CGFloat height = self.frame.size.width;
CGFloat scale = [UIScreen mainScreen].scale;
//防止圆角半径小于0,或大于宽/高中较小值的一半
if (cornerRadius < 0) {
cornerRadius = 0;
}else if(cornerRadius > MIN(width, height)){
cornerRadius = MIN(width, height) / 2;
}
UIImage *image = [UIImage new];
CGRect imageFrame = CGRectMake(0, 0, width, height);
UIGraphicsBeginImageContextWithOptions(self.frame.size, NO, scale);
[[UIBezierPath bezierPathWithRoundedRect:imageFrame cornerRadius:cornerRadius]addClip];
[self drawRect:imageFrame];
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
常⻅触发离屏渲染的⼏种情况
- 使⽤了mask的layer(layer.mask)
- 需要进⾏裁剪的layer(layer.masksToBounds/view.clipsToBounds)
- 设置了组透明度为YES,并且透明度不为1的layer(layer.allowsGroupOpacity/layer.opacity)
- 添加了投影的layer(layer.shadow*)
- 采⽤了光栅化的layer(layer.shouldRasterize)
- 绘制了⽂字的layer(UILabel,CATextLayer,CoreText等)