离屏渲染(二)

有哪些操作到导致离屏烘托?

一、 添加光栅化

光栅化是一个缓存机制,假如敞开了光栅化,它会将图片以一个bitmap位图的方法,保存起来,当下一次需求时分,CPU直接从缓存里拿出来交给GPU进行处理,这样GPU就不需求进行一些烘托的核算,光栅化便是一个能削减GPU核算的操作,光栅化是一个进步性能的操作。可是,日常使用光栅化的场景非常少,光栅化使用有限制,因为bitmap只能缓存100ms

//光栅化 
- (void)shouldRasterize {
    self.testImageView.layer.shouldRasterize = YES;
}

能够看到敞开光栅化会触发离屏烘托:

离屏渲染(二)

二、添加遮罩

- (void)setMask {
    //添加到layer的上层
    CALayer *layer = [CALayer layer];
    layer.frame = CGRectMake(30, 30, self.testImageView.bounds.size.width, self.testImageView.bounds.size.height);
    layer.backgroundColor = [UIColor redColor].CGColor;
    self.testImageView.layer.mask = layer;
}

会触发离屏烘托:

离屏渲染(二)

因为添加遮罩,创立出来的layer会被添加到原本图画的默认layer上面,而屏幕上的每一个像素点是通过多层layerGPU混合核算出来的,多添加了一层layer,便是相似上篇文章讲的,层级变杂乱了,这样GPU无法把需求出现的图画一次制作完毕,他只能用离屏烘托的方法来处理。

三、添加暗影

//暗影
- (void)setShadows {
    self.testImageView.layer.shadowColor = [UIColor redColor].CGColor;
    self.testImageView.layer.shadowOffset = CGSizeMake(20, 20);
    self.testImageView.layer.shadowOpacity = 0.2;
    self.testImageView.layer.shadowRadius = 5;
    self.testImageView.layer.masksToBounds = NO;
}

会触发离屏烘托:

离屏渲染(二)

这个暗影和遮罩mask是很像,只不过遮罩是添加到layer的上层,而暗影是添加到layer的基层,它的层级也比较杂乱,所以也会触发离屏烘托。

四、使用贝塞尔曲线进行优化

//暗影优化
- (void)setShadows2 {
    self.testImageView.layer.shadowColor = [UIColor redColor].CGColor;
    self.testImageView.layer.shadowOpacity = 0.2;
    self.testImageView.layer.shadowRadius = 5;
    self.testImageView.layer.masksToBounds = NO;
    //提前指定暗影的路径
    [self.testImageView.layer setShadowPath:[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, self.testImageView.bounds.size.width + 20, self.testImageView.bounds.size.height + 20)].CGPath];
}

没有离屏烘托:

离屏渲染(二)

暗影是添加在layer的基层,暗影会优先会被烘托,在烘托暗影的时分依靠视图的大小,但视图自身还没有被烘托好,这个时分只能通过离屏烘托进行辅佐处理,贝塞尔曲线便是提前指定暗影的路径,这个暗影的烘托就不需求依靠视图本体,这个暗影会被单独地进行烘托,不需求通过离屏烘托辅佐组成图画。

五、抗锯齿

//抗锯齿
- (void) setEdgeAnntialiasing {
    CGFloat angle = M_PI / 60.0;
    [self.testImageView.layer setTransform:CATransform3DRotate(self.testImageView.layer.transform, angle, 0.0, 0.0, 1.0)];
    self.testImageView.layer.allowsEdgeAntialiasing = YES;
} 

这个要分状况,在图片Content ModeAspect Fill的模式下:

离屏渲染(二)

会触发离屏烘托:

离屏渲染(二)

假如改为Scale To Fill或许Aspect Fit等不需求进行抗锯齿核算的模式就不会触发离屏烘托:

离屏渲染(二)

因此,icon的图片最好跟控件的份额或许尺度是相同的,最大或许地削减离屏烘托的或许性。

六、不透明

不透明也要分两种状况:

//不透明
- (void)allowsGroupOpacity {
  self.testImageView.alpha = 0.5;
  self.testImageView.layer.allowsGroupOpacity = YES;
}

1. 假如是自己自身不透明,并不会触发离屏烘托:

离屏渲染(二)

2. 一种还有子视图的状况敞开allowsGroupOpacity

- (void)allowGroupOpacity {
  UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
  view.backgroundColor = [UIColor greenColor];
  [self.testImageView addSubview:view];
  self.testImageView.alpha = 0.5;
    //allowsGroupOpacity 设置视图的子视图在透明度上是否和俯视图共同
  self.testImageView.layer.allowsGroupOpacity = YES;
}
  • 假如自身还有子视图,父视图不透明度小于1,敞开允许组不透明就需求混合核算,这样就会触发离屏烘托:

离屏渲染(二)

  • 假如自身还有子视图,父视图不透明度为1,敞开允许组不透明就需求混合核算,这样不会触发离屏烘托:

离屏渲染(二)

七、圆角

1. 设置布景色彩和圆角

- (void)setRadius {
    self.testImageView.backgroundColor = [UIColor redColor];
    self.testImageView.layer.cornerRadius = 45;
}

会触发离屏烘托:

离屏渲染(二)

2. 只设置圆角

不会触发:

离屏渲染(二)

3. 给子视图标签添加圆角和色彩

- (void)setRadius {
    self.testImageView.backgroundColor = [UIColor redColor];
    self.testImageView.layer.cornerRadius = 40;
    self.testLabel.backgroundColor = [UIColor greenColor];
    self.testLabel.layer.cornerRadius = 10;
}

发现绿色标签不会:

离屏渲染(二)

4. 假如给label的layer层添加色彩

- (void)setRadius {
    self.testImageView.backgroundColor = [UIColor redColor];
    self.testImageView.layer.cornerRadius = 40;
    self.testLabel.layer.backgroundColor = [UIColor greenColor].CGColor;
    self.testLabel.layer.cornerRadius = 10;
}

会触发离屏烘托:

离屏渲染(二)

因为labellayer设置布景色彩,它实践是给contents设置色彩

图片设置圆角的时分,实践是设置给borderbackgroundColor设置,不会设置contents,所以图片需求Clips to Bounds

离屏渲染(二)

iOS9之后给视图设置单纯设置圆角不会触发离屏烘托,可是假如一起操作contents + backgroundColor/border就会触发。

八、贝塞尔曲线

//贝塞尔曲线
- (void)setBezier {
    //开端上下文 UIGaphicsBeginImageContextWithOptions(self.testImageView.bounds.size, NO, 0.0);
    [[UIBezierPath bezierPathWithRoundedRect:self.testImageView.bounds cornerRadius:40] addClip];
    [self.testImageView drawRect:self.testImageView.bounds];
    //当时上下文
    self.testImageView.image = UIGraphicsGetImageFromCurrentImageContext();
    // 结束上下文
    UIGraphicsEndImageContext();
}

不会触发离屏烘托:

离屏渲染(二)

九、drawRect使用

-(void)drawRect:(CGRect)rect {
    //特别的离屏烘托
    //baking store -- bitmap
}

视图自身就有一块画布,drawRect会从头添加一块画布,会从头生成baking store,添加内存耗费,虽然检测不到,但也会触发离屏烘托,是特别的离屏烘托。