四、iOS离屏渲染

一、开启图层是否触发离屏渲染问题

注:离屏渲染的图层会标记为黄色

开启离屏渲染检测.png

二、离屏渲染的渲染流程

普通加载流程.png
离屏渲染流程.png

三、离屏渲染触发的原因

第一个原因:App进行额外的渲染和合并(复杂图层会自动离屏渲染)

App 进行额外的渲染和合并 ,这时必须要用 offscreen Buffer(离屏缓存区) 来进行 组合,把组合结果放在 FrameBuffer(帧缓存区),然后显示在屏幕上

1.1 什么情况下圆角会触发离屏渲染

当显示 三层,边框 、内存、背影颜色,三个进行叠加时 再加圆角 会触发离屏渲染

只设置 layer.cornerRadius ,只会设置 backgroundColor 和 border 的是圆角,不会设置 content(内容)的圆角,除非同时设置了 layer.masksToBounds 为 Ture (对应 view 中的 clipsToBounds 属性)才会对内容进行圆角。

1.2 毛玻璃会触发离屏渲染,毛玻璃触发离屏渲染是怎么做的?

1,拿到源图,2,缩放,3,平行模糊,4垂直模糊,之后将4个图层从离屏渲染中拿出来,合并得到最终的模糊效果,存在帧缓冲中
前面的4个结果,存在于离屏缓冲区,再进行合成。

第二个原因:光栅化(手动离屏渲染)

启用 shouldRasterize 光栅化时,就会进行复用,如果图层想要进行复用,可以做复用功能,开启光栅化。

什么情况下使用光栅化,光栅化(shouldRasterize ) 使用建议

1.如果 layer 不能被复用,则没有必要打开光栅化。
2.如果 layer 不是静态的,需要被频繁修改,比如处于动画之中。那么开启离屏渲染反而影响效率。
3.离屏渲染缓存内容有时间限制,缓存内容 100ms 内容如果没有被使用,那么它就会丢弃。无法再进行复用了。
4.离屏渲染缓存空间有限,超过 2.5 倍屏幕像素大小的话,也会失效,且无法进行复用。

四、渲染的原理

图层遮罩Mask ,使用 Mask 时会触发离屏渲染
第一步: 从App提交到 Core Animation (Render Server) -> Vertex Shader(顶点着色器,确定显示位置)-> 触发 Render渲染缓冲区 Pixel Shader(片元着色器,) -> 获得一个 Mask Texture (遮罩)【不能直接显示在帧缓冲区,需要暂时存放在中间缓冲区 offscreen Buffer 】
第二步 与第一步相同 获得 第二个 Mask Texture 存在离屏缓冲区
第三步:从两个离屏渲染缓冲区中 拿到数据,然后合并放在帧缓冲区

五、离屏渲染的绘制逻辑:

油画算法:先绘制远的图层,再绘制中间图层,再绘制近的图层,依次绘制


普通绘制逻辑.png
离屏渲染绘制逻辑.png

六、离屏渲染的性能

离屏渲染有性能问题?两点

1.离屏渲染需要额外的存储空间,大量离屏渲染会造成内存压力(Offscreen Buffer 空间是有限制的,是屏幕的2.5倍)
2.把结果从offscreen Buffer 转存在 FrameBuffer也需要时间

离屏渲染会造成性能问题,为什么还要用?

1.因为非常多的特殊效果,并不能够一次性用一个图层就能画出来(不能一次性得到结果),需要使用额外的offscreenBuffer 保存中间状态,这时不得不使用离屏渲染[系统自动触发,圆角 阴影]
2.效率的优势:既然效果会多次出现在屏幕上,我们可以提前渲染好,保存在offscreenBuffer,从而达到复用目的。[手动触发]

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

  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 (UITextLabel, CATextLayer, Core Text 等)

八、案例:

触发离屏渲染案例.png
  1. 背景色+图片+边框 -> 不会触发离屏渲染
//     背景色+图片+边框 -> 不会触发离屏渲染
    UIView *view1 = [[UIView alloc] init];
    view1.frame = CGRectMake(50, 50, 100, 100);
    [self.view addSubview:view1];
    view1.backgroundColor = [UIColor grayColor];
    view1.layer.borderColor = [UIColor redColor].CGColor;
    view1.layer.borderWidth = 5;
    CALayer *imgLayer1 = [CALayer layer];
    imgLayer1.frame = CGRectMake(10, 10, 80, 80);
    imgLayer1.contents = (__bridge id)[UIImage imageNamed:@"btn.png"].CGImage;
    [view1.layer addSublayer:imgLayer1];

2.背景色+图片+边框+圆角 -> 不会触发离屏渲染

    // 背景色+图片+边框+圆角 -> 不会触发离屏渲染
    UIView *view2 = [[UIView alloc] init];
    view2.frame = CGRectMake(250, 50, 100, 100);
    [self.view addSubview:view2];
    view2.backgroundColor = [UIColor grayColor];
    view2.layer.borderColor = [UIColor redColor].CGColor;
    view2.layer.borderWidth = 5;
    CALayer *imgLayer2 = [CALayer layer];
    imgLayer2.frame = CGRectMake(10, 10, 80, 80);
    imgLayer2.contents = (__bridge id)[UIImage imageNamed:@"btn.png"].CGImage;
    [view2.layer addSublayer:imgLayer2];
    view2.layer.cornerRadius = 50;

3.背景色+图片+边框+圆角+裁剪mask -> 会触发离屏渲染

    // 背景色+图片+边框+圆角+裁剪mask -> 会触发离屏渲染
    UIView *view3 = [[UIView alloc] init];
    view3.frame = CGRectMake(50, 200, 100, 100);
    [self.view addSubview:view3];
    view3.backgroundColor = [UIColor grayColor];
    view3.layer.borderColor = [UIColor redColor].CGColor;
    view3.layer.borderWidth = 5;
    CALayer *imgLayer3 = [CALayer layer];
    imgLayer3.frame = CGRectMake(10, 10, 80, 80);
    imgLayer3.contents = (__bridge id)[UIImage imageNamed:@"btn.png"].CGImage;
    [view3.layer addSublayer:imgLayer3];
    view3.layer.cornerRadius = 50;
    view3.layer.masksToBounds = YES;

4.设置了组透明度为YES -> 会触发离屏渲染

//    设置了组透明度为YES -> 会触发离屏渲染
    UIView *view4 = [[UIView alloc] init];
    view4.frame = CGRectMake(250, 200, 100, 100);
    [self.view addSubview:view4];
    view4.layer.contents = (__bridge id)[UIImage imageNamed:@"btn.png"].CGImage;
    view4.layer.shouldRasterize = YES;// 组透明

5.添加了投影的layer -> 会触发离屏渲染

//    添加了投影的layer -> 会触发离屏渲染
    UIView *view5 = [[UIView alloc] init];
    view5.frame = CGRectMake(50, 340, 100, 100);
    [self.view addSubview:view5];
    view5.layer.contents = (__bridge id)[UIImage imageNamed:@"btn.png"].CGImage;
    view5.layer.shadowColor = [UIColor blackColor].CGColor;//shadowColor阴影颜色
    view5.layer.shadowOffset = CGSizeMake(2,6);//shadowOffset阴影偏移
     view5.layer.shadowOpacity = 0.7;//阴影透明度,默认0

6.UITextView绘制文字+圆角+mask -> 会触发离屏渲染

//    UITextView绘制文字+圆角+mask -> 会触发离屏渲染
    UITextView *textLabel = [[UITextView alloc] initWithFrame:CGRectMake(250, 340, 100, 100)];
    [self.view addSubview:textLabel];
    textLabel.text = @"    UITextView\n    文字内容";
    textLabel.layer.cornerRadius = 50;
    textLabel.layer.masksToBounds = YES;

  1. UILabel绘制文字+背景色+圆角+mask -> 不会触发离屏渲染
    // UILabel绘制文字+背景色+圆角+mask -> 不会触发离屏渲染
    UILabel *txtLabel = [[UILabel alloc] initWithFrame:CGRectMake(50, 500, 100, 100)];
    [self.view addSubview:txtLabel];
    txtLabel.text = @"    UILabel\n    文字内容";
    txtLabel.numberOfLines = 2;
    txtLabel.backgroundColor = [UIColor redColor];
    txtLabel.layer.cornerRadius = 50;
    txtLabel.layer.masksToBounds = YES;

121.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354