离屏渲染

作者: 恍然如梦_b700 | 来源:发表于2020-07-08 16:55 被阅读0次

离屏渲染检测

image.png
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    //1.按钮存在背景图片
    UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
    btn1.frame = CGRectMake(100, 30, 100, 100);
    btn1.layer.cornerRadius = 50;
    [self.view addSubview:btn1];
    
    [btn1 setImage:[UIImage imageNamed:@"btn.png"] forState:UIControlStateNormal];
    btn1.clipsToBounds = YES;
    
    //2.按钮不存在背景图片
    UIButton *btn2 = [UIButton buttonWithType:UIButtonTypeCustom];
    btn2.frame = CGRectMake(100, 180, 100, 100);
    btn2.layer.cornerRadius = 50;
    btn2.backgroundColor = [UIColor blueColor];
    [self.view addSubview:btn2];
    btn2.clipsToBounds = YES;
    
    //3.UIImageView 设置了图片+背景色;
    UIImageView *img1 = [[UIImageView alloc]init];
    img1.frame = CGRectMake(100, 320, 100, 100);
    img1.backgroundColor = [UIColor blueColor];
    [self.view addSubview:img1];
    img1.layer.cornerRadius = 50;
    img1.layer.masksToBounds = YES;
    img1.image = [UIImage imageNamed:@"btn.png"];
    
    //4.UIImageView 只设置了图片,无背景色;
    UIImageView *img2 = [[UIImageView alloc]init];
    img2.frame = CGRectMake(100, 480, 100, 100);
    [self.view addSubview:img2];
    img2.layer.cornerRadius = 50;
    img2.layer.masksToBounds = YES;
    img2.image = [UIImage imageNamed:@"btn.png"];
    
}

为什么1、3会触发离屏渲染?
1 设置layer的圆角,设置了背景图片,存在两个layer ,并且进行了裁剪
3 同样的道理有两个图层,并且进行了裁剪
2只有一个图层,即使裁剪了,直接进行绘制也可以到达效果
4的图层只有一个content图层,所以也不会触发离屏渲染

离屏渲染

app进行额外的渲染与合并,数据会在offScreen Buffer组合,然后转交给FrameBuffer,显示到屏幕上
离屏渲染需要额外的存储空间,大小是屏幕像素点的2.5倍

离屏渲染会对性能有影响,但是为什么离屏渲染还存在呢?
1.比如特殊效果,要使用额外的offScreenBuffer保持中间状态,不得不使用,
2.可以提高效率,假如一个效果可能多次被屏幕使用,那么提前渲染将数据保存在offScreenBuffer,就可以达到复用目的

圆角触发离屏渲染解读

先看看圆角的显示图层:


image.png

设置圆角并不是触发圆角的主要原因,我们来看看苹果官方对cornorRadius的介绍


image.png

设置layer.cornorRadius只会设置backgroundColor和border的圆角,并不会设置content的圆角,除非设置了layer.maskToBounds为True(对应View中的ClipsToBoundss属性)

非离屏渲染时当sublayer绘制到屏幕上之后,就会将sublayer从帧缓存区中移除,从而节省空间, 但是如果需要设置圆角裁剪等,很显然,多个叠加在一起的图层无法达到效果,因为无法计算
而离屏渲染,会在offscreen Buffer缓存sublayer,最终将几个sublayer组合起来显示

iOS 圆角的处理方案

1.单图层clips

imageView.clipsToBounds = true
imageView.layer.cornorRadius = 2

2.使用CoreGraphics + 贝塞尔绘制

·(UIImage *)roundedCornerImageWithCornerRadius:(CGFloat)cornerRadius {
CGFloat w=self.size.width;
CGFloat h= self.size.height;
CGFloat scale =[UIScreen mainScreenl].scale;
// 防止圆角半径小于0,或者大于宽/高中较小值的一半。
if(cornerRadius < 6)
cornerRadius = 6;
else if(cornerRadius >MIN(w, h))
cornerRadius = MIN(w,h)/2.;
UIImage *image=nil;
CGRect imageFrame= CGRectMake(0.,0., w, h);
UIGraphicsBeginImageContextwithOptions(seLf.size, NO, scale);
[[UIBezierPath bezierPathwithRoundedRect:imageframe cornerRadius:cornerRadius] addCLipl [self drawInRect:imageFramel;
image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;

3.使用CoreGraphics + 贝塞尔绘制

-(void)addMaskToBounds:(CGRect)maskBounds{
CGFloatw= maskBounds.size.width;
CGFloat; h = maskBounds.size.height;
CGSize size = maskBounds.size;
CGFLoat scale =[UIScreen mainScreen].scale;
CGRect imageRect = CGRectMake(6,8,w, h);
if(self.cornerRadius < 0){
self.cornerRadius = 0;
lelse if(self.cornerRadius >MIN(w, h)){\
self.cornerRadius =MIN(w,h)/2;
l
UIImage *image = self.image;
UIGraphicsBeginImageContextwithOptions(size, NO, scale);
[[UIBezierPath bezierPathwithRoundedRect:imageRect cornerRadius:self.cornerRadiusl addClip];
[image drawInRect:imageRect];
self.roundImage = UIGraphicsGetImageFromCurrentImageContext();
self.image = self.roundImage;
UIGraphicsEndImageContext();
)

4.盖上一个透明图片

5.YYImage的处理方法

- (UIImage *)yy_imageByRoundCornerRadius:(CGFloat)radius
                                 corners:(UIRectCorner)corners
                             borderWidth:(CGFloat)borderWidth
                             borderColor:(UIColor *)borderColor
                          borderLineJoin:(CGLineJoin)borderLineJoin {
    
    if (corners != UIRectCornerAllCorners) {
        UIRectCorner tmp = 0;
        if (corners & UIRectCornerTopLeft) tmp |= UIRectCornerBottomLeft;
        if (corners & UIRectCornerTopRight) tmp |= UIRectCornerBottomRight;
        if (corners & UIRectCornerBottomLeft) tmp |= UIRectCornerTopLeft;
        if (corners & UIRectCornerBottomRight) tmp |= UIRectCornerTopRight;
        corners = tmp;
    }
    
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
    CGContextScaleCTM(context, 1, -1);
    CGContextTranslateCTM(context, 0, -rect.size.height);
    
    CGFloat minSize = MIN(self.size.width, self.size.height);
    if (borderWidth < minSize / 2) {
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectInset(rect, borderWidth, borderWidth) byRoundingCorners:corners cornerRadii:CGSizeMake(radius, borderWidth)];
        [path closePath];
        
        CGContextSaveGState(context);
        [path addClip];
        CGContextDrawImage(context, rect, self.CGImage);
        CGContextRestoreGState(context);
    }
    
    if (borderColor && borderWidth < minSize / 2 && borderWidth > 0) {
        CGFloat strokeInset = (floor(borderWidth * self.scale) + 0.5) / self.scale;
        CGRect strokeRect = CGRectInset(rect, strokeInset, strokeInset);
        CGFloat strokeRadius = radius > self.scale / 2 ? radius - self.scale / 2 : 0;
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:strokeRect byRoundingCorners:corners cornerRadii:CGSizeMake(strokeRadius, borderWidth)];
        [path closePath];
        
        path.lineWidth = borderWidth;
        path.lineJoinStyle = borderLineJoin;
        [borderColor setStroke];
        [path stroke];
    }
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

常见触发离屏渲染的几种情况

1.使用了mask的layer(layer.mask)
2.需要进行裁剪的layer(layer.maskToBounds/view.clipsToBounds),并且有多个layer
3.设置了组透明度为YES,并且透明度不为 1 的 layer (layer.allowsGroupOpacity/
layer.opacity)
4.添加了投影的layer(layer.shadow)
5.采用了光栅化的layer (layer.shouldRasterize)
6.绘制了文字的layer (UILabel, CATextLayer, Core Text 等)
7.开启了抗锯齿

相关文章

  • iOS--离屏渲染

    离屏渲染(Offscreen rendering) 离屏渲染的定义 离屏渲染(offscreen-renderin...

  • 图层性能-离屏渲染、光栅化等

    一.离屏渲染 1.在屏渲染、离屏渲染: On-Screen Rendering/在屏渲染:在屏渲染:指的是GPU的...

  • 关于离屏渲染

    1.什么是离屏渲染 2.离屏渲染的触发方式 3.离屏渲染的意义 4.离屏渲染的不足 1.什么是离屏渲染 要了解离屏...

  • 四、iOS离屏渲染

    一、开启图层是否触发离屏渲染问题 注:离屏渲染的图层会标记为黄色 二、离屏渲染的渲染流程 三、离屏渲染触发的原因 ...

  • UI视图及UITableView流畅性优化

    一.离屏渲染 1. 在屏渲染和离屏渲染 在屏渲染是指在当前用于显示的屏幕缓冲区进行GPU渲染操作 离屏渲染是指在当...

  • iOS下对离屏渲染的理解

    离屏渲染定义 离屏渲染的流程如图: GPU把渲染好的的内容存放到离屏渲染缓冲区中,在离屏渲染缓冲区(Offscre...

  • iOS渲染

    离屏渲染两种:CPU离屏渲染:1、使用 core graphics2、在 drawrect 中执行 GPU离屏渲染...

  • 003-iOS离屏渲染产生的原因

    离屏渲染产生的原因 在讨论离屏渲染之前我们先要搞清楚正常的渲染流程是怎样的 非离屏渲染流程: 我们可以看到在非离屏...

  • 离屏渲染引发的反思

    经常看到说是离屏渲染会影响性能,我们要避免离屏渲染,然后阐述离屏渲染的触发情况有哪些? 既然离屏渲染那么不好,那为...

  • 四、离屏渲染

    离屏渲染与正常渲染 屏幕上最终显示的数据有两种加载流程 正常渲染加载流程 离屏渲染加载流程离屏渲染与正常渲染 常⻅...

网友评论

    本文标题:离屏渲染

    本文链接:https://www.haomeiwen.com/subject/qqlccktx.html