笔记-圆角四种方法的对比以及性能检测

4,205 阅读4分钟

这篇文章是继笔记-iOS设置圆角方法以及指定位置设圆角文章而写的,因为上篇文章发出来后,没有验证,也有同行的朋友让我给出一些测试数据来证实一下,所以这里就给出一下我个人的一些测试数据,正确是否,还请大家作为参考。--------另外,我写这个仅仅只是自己作为笔记使用,原来都是放在草稿里的,但是手机版的无法查看草稿,所以就发出来,没有想过会有人来看,所以如果有错误的内容误导了大家请原谅,也请发现错误的猿友及时帮忙提出,谢谢大家。

Core Animation工具检测离屏渲染

对离屏渲染的检测,苹果为我们提供了一个测试工具Core Animation。可以在Xcode->Open Develeper Tools->Instruments中找到。

先看看第一种方式:通过设置layer的属性

对UIImageview设置:

结果: 无离屏渲染

滚动的帧率:

结果: 接近60,趋于稳定

对UIButton设置:

结果: 离屏渲染

滚动的帧率:

如果低于40帧每秒,普通用户就会察觉明显的不流畅,现在这样app进入垃圾级别体验了。

对于文本视图实现圆角(UILabel, UIView, UITextField, UITextView

均只进行cornerRadius设置,不进行masksToBounds的设置

离屏渲染情况:

从上图可以看出,对于UILabel, UIView, UITextField来说,实现了圆角的设置,并没有产生离屏渲染;而对于UITextView,产生了离屏渲染。

滚动的帧率:
不存在UITextView视图的情况下

存在UITextView视图的情况下

官方对离屏渲染产生性能问题也进行了优化:

iOS9.0之前UIImageView跟UIButton设置圆角都会触发离屏渲染。

iOS9.0之后UIButton设置圆角会触发离屏渲染,而UIImageView设置圆角不会触发离屏渲染了,但是如果设置其他阴影效果之类的还是会触发离屏渲染

第二种方式:使用贝塞尔曲线UIBezierPath和Core Graphics框架画出一个圆角

对UIImageview设置:
帧率结果:

对UIButton设置:
帧率结果:

两种设置均是无离屏渲染

第三种方式:使用Core Graphics框架画出一个圆角

对UIImageview设置:
帧率结果:

对UIButton设置:
帧率结果:

两种设置均是无离屏渲染

第四种方式:使用CAShapeLayer和UIBezierPath设置圆角

对UIImageview、UIButton设置:
帧率结果:

两种都是离屏渲染,掉帧更加严重。基本上不能使用。

由上述测试可以知道,我上篇文章里所记笔记是有问题的。这里的测试结果可以看的彻底。

新方法:实际可采取利用

混合图层

在需要裁剪的视图上面添加一层视图,以达到圆角的效果。效果如下:

布局图如下:

对于UIImageViewUIButton均可使用,且无离屏渲染

滚动的帧率:

代码如下:

- (void)drawRoundedCornerImage {
    UIImageView *iconImgV = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    iconImgV.image = [UIImage imageNamed:@"icon"];
    [self.view addSubview:iconImgV];
    
    [iconImgV mas_makeConstraints:^(MASConstraintMaker *make) {
        make.size.mas_equalTo(iconImgV.size);
        make.top.equalTo(self.view.mas_top).offset(500);
        make.centerX.equalTo(self.view);
    }];
    
    UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
    [self.view addSubview:imgView];
    
    [imgView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.size.mas_equalTo(imgView.size);
        make.top.equalTo(iconImgV.mas_top);
        make.leading.equalTo(iconImgV.mas_leading);
    }];
    
    // 圆形
    imgView.image = [self drawCircleRadius:100 outerSize:CGSizeMake(200, 200) fillColor:[UIColor whiteColor]];
}

// 绘制圆形
- (UIImage *)drawCircleRadius:(float)radius outerSize:(CGSize)outerSize fillColor:(UIColor *)fillColor {
    UIGraphicsBeginImageContextWithOptions(outerSize, false, [UIScreen mainScreen].scale);
    
    // 1、获取当前上下文
    CGContextRef contextRef = UIGraphicsGetCurrentContext();
    
    //2.描述路径
    // ArcCenter:中心点 radius:半径 startAngle起始角度 endAngle结束角度 clockwise:是否逆时针
    UIBezierPath *bezierPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(outerSize.width * 0.5, outerSize.height * 0.5) radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:NO];
    [bezierPath closePath];
    
    // 3.外边
    [bezierPath moveToPoint:CGPointMake(0, 0)];
    [bezierPath addLineToPoint:CGPointMake(outerSize.width, 0)];
    [bezierPath addLineToPoint:CGPointMake(outerSize.width, outerSize.height)];
    [bezierPath addLineToPoint:CGPointMake(0, outerSize.height)];
    [bezierPath addLineToPoint:CGPointMake(0, 0)];
    [bezierPath closePath];
    
    //4.设置颜色
    [fillColor setFill];
    [bezierPath fill];
    
    CGContextDrawPath(contextRef, kCGPathStroke);
    UIImage *antiRoundedCornerImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return antiRoundedCornerImage;
}

此方法就是在要添加的视图上在叠加一个部分透明的视图,只对圆角部分进行遮挡。图层混合的透明度处理方式与mask正好相反。 此方法没有离屏渲染,也可以自定义设置指定任意角为圆角。

总结

  • 在可以使用混合图层遮挡的场景下,优先使用。
  • 通过.layer属性设置,综合性能上,还是有很大优势的。