什么是離屏渲染
Off-Screen Rendering意為離屏渲染,指的是GPU在當(dāng)前屏幕緩沖區(qū)以外新開辟一個(gè)緩沖區(qū)進(jìn)行渲染操作
為什么需要離屏渲染
因?yàn)樵趲彌_區(qū)渲染一個(gè)視圖到屏幕中就拋棄的機(jī)制.所以當(dāng)我們有多組視圖需要組合隨后統(tǒng)一處理的時(shí)候.需要在屏緩沖區(qū)額外開辟一個(gè)離屏的緩沖區(qū)去記錄這些視圖.隨后統(tǒng)一處理.最后渲染顯示出來

怎么產(chǎn)生離屏渲染
我們首先分析圓角產(chǎn)生離屏渲染的情況:
回顧一下.當(dāng)我們給一個(gè)視圖添加cornerRadius時(shí).是給哪些視圖添加了圓角?
蘋果官方的解答是:
Setting the radius to a value greater than 0.0 causes the layer to begin drawing rounded corners on its background. By default, the corner radius does not apply to the image in the layer’s contents property; it applies only to the background color and border of the layer. However, setting the masksToBounds property to YES causes the content to be clipped to the rounded corners.The default value of this property is 0.0.
即背景視圖以及邊框等視圖,不包含contents視圖.所以當(dāng)我們只設(shè)置cornerRadius時(shí).不設(shè)置masksToBounds為YES.視圖視覺上還是沒產(chǎn)生圓角

隨后我們對以下四種情況分別做圓角處理
a.按鈕視圖設(shè)置圖片.并且設(shè)置圓角cornerRadius和裁剪masksToBounds.會(huì)產(chǎn)生離屏渲染
b.按鈕視圖不設(shè)置圖片.設(shè)置圓角cornerRadius和裁剪masksToBounds.不會(huì)產(chǎn)生離屏渲染
c.圖片視圖不設(shè)置背景色.設(shè)置圓角cornerRadius和裁剪masksToBounds.不會(huì)產(chǎn)生離屏渲染
d.圖片視圖設(shè)置背景色.設(shè)置圓角cornerRadius和裁剪masksToBounds.會(huì)產(chǎn)生離屏渲染
相關(guān)代碼如下:
//設(shè)置圖片會(huì)產(chǎn)生離屏渲染
UIButton * btn1 = [UIButton buttonWithType:(UIButtonTypeCustom)];
btn1.frame = CGRectMake(100, 30, 100, 100);
[btn1 setImage:[UIImage imageNamed:@"WX20201127-92813"] forState:UIControlStateNormal];
[self.view addSubview:btn1];
btn1.layer.cornerRadius = 50;
btn1.layer.masksToBounds = YES;
//只設(shè)置背景色不會(huì)產(chǎn)生離屏渲染
UIButton * btn2 = [UIButton buttonWithType:(UIButtonTypeCustom)];
btn2.frame = CGRectMake(100, 150, 100, 100);
btn2.backgroundColor = UIColor.grayColor;
[self.view addSubview:btn2];
btn2.layer.cornerRadius = 50;
btn2.layer.masksToBounds = YES;
//對于圖片來說.設(shè)置背景色以及圖片就會(huì)產(chǎn)生離屏渲染.不設(shè)置就不會(huì)
UIImageView * img1 = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"WX20201127-92813"]];
img1.frame = CGRectMake(100, 270, 100, 100);
img1.backgroundColor = UIColor.blueColor;
img1.layer.cornerRadius = 50;
img1.layer.masksToBounds = YES;
[self.view addSubview:img1];
UIImageView * img2 = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"WX20201127-92813"]];
img2.frame = CGRectMake(100, 390, 100, 100);
img2.layer.cornerRadius = 50;
img2.layer.masksToBounds = YES;
[self.view addSubview:img2];
效果如下:
那什么情況下會(huì)產(chǎn)生離屏渲染呢?
我們得出的表象結(jié)論是:
1.按鈕添加圖片以后做圓角處理
2.圖片視圖添加背景色和圖片以后做圓角處理
接下來.我們將img2進(jìn)行改進(jìn): 給tempView不加背景色不會(huì)產(chǎn)生離屏渲染.給tempView添加背景色還是會(huì)產(chǎn)生離屏渲染
UIImageView * img3 = [[UIImageView alloc]init];
img3.frame = CGRectMake(100, 510, 100, 100);
img3.layer.cornerRadius = 50;
img3.layer.masksToBounds = YES;
[self.view addSubview:img3];
UIView *tempView = [[UIView alloc]init];
tempView.backgroundColor = UIColor.redColor;
tempView.frame = img3.bounds;
[img3 addSubview:tempView];

由此我們可以知道:當(dāng)我們需要對多個(gè)圖層進(jìn)行組合處理時(shí)就需要使用到離屏渲染技術(shù).將多個(gè)圖層組合渲染完畢以后放到幀緩沖區(qū).顯示到屏幕中
需要注意的是.以上是組合.而不是疊加.
那么我們平時(shí)使用的視圖有哪些是組合.并且需要做離屏渲染的呢?
2.mask遮罩
3.光柵化
4.組合視圖設(shè)置透明度
5.陰影
6.漸變
7.繪制文字
8.系統(tǒng)毛玻璃效果
如何避免離屏渲染?
1.針對圓角的離屏渲染的情況.我們可以通過四種方案.
a.使用一個(gè)鏤空圓角視圖蓋在上面
b.使用YYImage里面的圓角方法
C.通過CALayer與UIBezierPath結(jié)合使用的
UIGraphicsBeginImageContextWithOptions(size, false, scale)
UIBezierPath.init(roundedRect: imgRect, cornerRadius: self.layer.cornerRadius).addClip()
self.image?.draw(in: imgRect)
self.image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
2.如果視圖不能被復(fù)用.并且不是靜態(tài).需要被頻繁修改的情況不建議開啟光柵化.因?yàn)檫@樣會(huì)開啟離屏渲染會(huì)影響效率
3.盡量少使用或不使用透明度
4.異步繪制.減少圖層
題外話:
1.離屏渲染緩存內(nèi)容有時(shí)間限制.緩存內(nèi)容100ms內(nèi)容如果沒有被使用.那么它就會(huì)丟棄.無法進(jìn)行復(fù)用
2.離屏渲染緩存空間有限.超過2.5倍屏幕像素大小的話.也會(huì)失效.且無法進(jìn)行復(fù)用了