美文网首页
探索iOS离屏渲染

探索iOS离屏渲染

作者: Gumball_a45f | 来源:发表于2020-07-09 11:36 被阅读0次

    离屏渲染

    探索之前可以先了解一些CALayer的基础

    我们都知道使用系统提供的设置圆角方法也会触发离屏渲染

    view.layer.cornerRadius = 5
    view.layer.masksToBounds = true
    

    为什么用圆角讲起,应为这个方法是我们平时经常会用到的,比较好理解一点。

    上面两行代码是一起才会引发的离屏渲染,还是某一行引起的呢?

    view.layer.cornerRadius = 5这行代码做了什么事?文档中cornerRadius属性中说明

    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.

    从此说明中我们可以知道,view.layer.cornerRadius只对背景颜色和前景框有效果,无法对contents进行设置,再看CALayer的结构,如果contents中有内容或内容的背景不是透明的话,还需要设置这部分的内容,否则没有效果。所以才需要修改 view.layer.masksToBoundstrue(在 UIView 上对应的属性是clipsToBounds)。

    之前有文章指出是修改view.layer.masksToBoundstrue才是触发离屏渲染的原因,而非修改cornerRadius。

    对此我们通过简单的代码来进行测试
    首先得打开模拟器的离屏渲染测试


    image.png

    1.圆角触发离屏渲染测试

    第一次测试:不设置masksToBoundsclipsToBounds
        UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200.0, 200.0)];
        // 设置背景色
        view1.backgroundColor = UIColor.blueColor;
        // 设置边框宽度和颜色
        view1.layer.borderWidth = 2.0;
        view1.layer.borderColor = UIColor.redColor.CGColor;
        // 设置圆角
        view1.layer.cornerRadius = 100.0;
        
        view1.center = self.view.center;
        [self.view addSubview:view1];
    

    结果我们发现确实没有发生离屏渲染:


    image.png
    第二次测试:

    同时设置masksToBoundscornerRadius

        UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200.0, 200.0)];
        // 设置背景色
        view1.backgroundColor = UIColor.blueColor;
        // 设置边框宽度和颜色
        view1.layer.borderWidth = 2.0;
        view1.layer.borderColor = UIColor.redColor.CGColor;
        // 设置圆角
        view1.layer.cornerRadius = 100.0;
        
        // 设置裁剪
        view1.clipsToBounds = YES;
        view1.center = self.view.center;
        [self.view addSubview:view1];
    

    结果还是没有发生离屏渲染:


    image.png

    这是为什么呢?
    原来我们还没设置contents,在CALayer的基础中有说过contents它必须是一个CGImage才能显示。
    下面我们将给contents赋值一个CGImage

     //设置图片
     view1.layer.contents = (__bridge id)[UIImage imageNamed:@"zhu24.jpg"].CGImage;
    

    结果触发了离屏渲染


    image.png

    因此可以知道当我们同时设置masksToBoundscornerRadius,并且contents是有内容的时候,会触发离屏渲染。

    但并没有解决我们的疑问

    下面我们测试只开启masksToBounds
            UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200.0, 200.0)];
            // 设置背景色
            view1.backgroundColor = UIColor.blueColor;
            // 设置边框宽度和颜色
            view1.layer.borderWidth = 2.0;
            view1.layer.borderColor = UIColor.redColor.CGColor;
            
            //设置图片
            view1.layer.contents = (__bridge id)[UIImage imageNamed:@"zhu24.jpg"].CGImage;
            
            // 设置裁剪
            view1.clipsToBounds = YES;
            view1.center = self.view.center;
            [self.view addSubview:view1];
    

    结果是没有触发离屏渲染的


    image.png

    可能也是因为view1的图形压根就没有发生改变,所以没有触发也是正常现象。
    不过从中我们可以知道这两个属性单独作用时都不是引发离屏渲染的原因,他俩合体(masksToBounds = true&&cornerRadius>0)才是。

    最后测试一下当CALayer中只有contents有内容,背景和边框为空
    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200.0, 200.0)];
    //设置图片
    view1.layer.contents = (__bridge id)[UIImage imageNamed:@"zhu24.jpg"].CGImage; 
    // 设置圆角
    view1.layer.cornerRadius = 100.0;
    // 设置裁剪
    view1.clipsToBounds = YES;
    view1.center = self.view.center;
    [self.view addSubview:view1];
    

    结果没有触发离屏渲染


    image.png

    所以触发离屏渲染还需要有多个图层。

    2. 离屏渲染的逻辑

    • 正常我们将图像渲染到屏幕上是遵循\color{red}{画家算法}

    油画算法:先绘制场景中的离观察者较远的物体,再绘制较近的物体。


    image.png

    当subLayer1绘制到屏幕后会立即从帧缓冲区(Offscreen Buffer)移除,从而节省空间。

    • 当我们应用cornerRadiusmaskToBounds进行圆角+裁剪时

    image.png

    绘制后并不会立即从帧缓冲区移除,而是依次在帧缓冲区中保存,等待圆角+裁剪处理,即引发了 离屏渲染 。

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

    1. 使⽤了 mask 的 layer (layer.mask)
    2. 需要进⾏裁剪的 layer (layer.masksToBounds / view.clipsToBounds)
    3. 设置了组透明度为 YES,并且透明度不为 1 的 layer (layer.allowsGroupOpacity/
      layer.opacity)
    4. 添加了投影的 layer (layer.shadow*)
    5. 采⽤了光栅化的 layer (layer.shouldRasterize)
    6. 绘制了⽂字的 layer (UILabel, CATextLayer, Core Text 等)

    相关文章

      网友评论

          本文标题:探索iOS离屏渲染

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