美文网首页
iOS离屏渲染的检测和优化

iOS离屏渲染的检测和优化

作者: shawnr | 来源:发表于2020-07-17 19:52 被阅读0次

iOS离屏渲染介绍了离屏渲染的逻辑和原理,我们知道离屏渲染对于性能会有较大的消耗,那么开发中怎么避免产生离屏渲染或者优化离屏渲染呢?

离屏渲染的检测
  1. Debug功能调试
    打开的Debug --> Color Off-screen Rendered


    simulator-debug.png

Color Off-screen Rendered 开启后会把那些需要离屏渲染的图层高亮成黄色,这就意味着黄色图层可能存在性能问题。

  1. 离屏渲染的优化
  • 针对图片圆角的优化
    ①. 苹果系统对圆角优化
    在设置圆角的情况下,必须明白一点儿是简单的图形是不会产生离屏渲染的,比如:
UIButton *cornerBtn = [[UIButton alloc] initWithFrame:CGRectMake(60, 88, 80, 60)];
cornerBtn.backgroundColor = [UIColor redColor];
[cornerBtn setTitle:@"这是按钮" forState:UIControlStateNormal];
cornerBtn.layer.cornerRadius = 30.f;
//cornerBtn.layer.masksToBounds = YES;
[self.view addSubview:cornerBtn];

所以不裁剪子视图设置圆角的情况下是不会产生离屏渲染的
在iOS9之后苹果系统对圆角进行了优化,UIImageView和UILabel即使使用了layer.masksToBounds = YES;仍然不会产生离屏渲染,但是UIButton如果使用layer.masksToBounds = YES剪切子视图仍然会产生离屏渲染

②. 对图片进行提前切圆角的操作:

@implementation UIImage (Extension)
- (UIImage *)roundedCOrnerImageWithCornerRadius:(CGFloat)cornerRadius {
    CGFloat w = self.size.width;
    CGFloat h = self.size.height;
    CGFloat scale = [UIScreen mainScreen].scale;
    if (cornerRadius < 0 ) {
        cornerRadius = 0;
    } else if (cornerRadius > MIN(w, h)) {
        cornerRadius = MIN(w, h) / 2.f;
    }
    UIImage *image;
    CGRect imageFrame = CGRectMake(0, 0, w, h);
    UIGraphicsBeginImageContextWithOptions(self.size, NO, scale);
    [[UIBezierPath bezierPathWithRoundedRect:imageFrame cornerRadius:cornerRadius] addClip];
    [self drawInRect:imageFrame];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}
@end

需要注意的是对图片切圆角时,最终的圆角是可能有缩放的,比如图片的尺寸imgSize为(100,200)而UIImageView的尺寸为(50,50)圆角尺寸如果为10,那么最终的效果是(100,200)的图片圆角为10,显示到UIImageView上x轴方向缩放2倍,y轴方向缩放4倍,所以这种方案缺点比较明显。
③. 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;
}

YYImage本质和第一种方案相同,都是对image的切圆角操作
④. 让UI切一个中间透明的镂空图片覆盖在UIImageView上

  • 针对阴影的优化
    对于shadow,我们可以通过设置shadowPath来优化性能,能大幅提高性能。如:
UIBezierPath *path=[UIBezierPath bezierPathWithRect:shadowView.bounds];
shadowView.layer.shadowPath = path.CGPath;

相关文章

  • iOS离屏渲染相关值得看的博客

    博客链接 iOS离屏渲染优化 绘制像素到屏幕上 关于iOS离屏渲染的深入研究 https://texturegro...

  • 卡顿优化

    卡顿优化 - CPU 卡顿优化 - GPU 离屏渲染 卡顿检测 耗电优化

  • iOS-离屏渲染探索

    iOS项目性能优化时,不得不提到离屏渲染,为了提升性能,我们要求尽量减少离屏渲染的发生。 那,什么是离屏渲染?离屏...

  • iOS离屏渲染的检测和优化

    在iOS离屏渲染介绍了离屏渲染的逻辑和原理,我们知道离屏渲染对于性能会有较大的消耗,那么开发中怎么避免产生离屏渲染...

  • iOS 性能优化

    iOS App 启动性能优化iOS离屏渲染优化(附DEMO) iOS Objective-C 数组遍历的性能及原理...

  • iOS性能优化笔记

    本文收录一些基本的性能优化的方法: iOS 离屏渲染优化(Offscreen Render)

  • 2018-07-04

    后台绘制圆角图片 参考链接链接 iOS 离屏渲染优化(Offscreen Render)

  • 离屏渲染

    iOS离屏渲染优化(附DEMO) - CocoaChina_让移动开发更简单

  • iOS 性能优化二

    主要讲解界面卡顿原因/优化方案/离屏渲染 iOS 性能优化一iOS 性能优化二iOS 性能优化三 1. 开发中遇到...

  • CALayer属性及优化

    iOS性能优化中的离屏渲染 场景:当使用圆角,阴影,遮罩的时候 为什么离屏渲染会造成性能消耗: 屏幕外渲染并不意味...

网友评论

      本文标题:iOS离屏渲染的检测和优化

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