iOS 切圆角离屏渲染问题

GPU屏幕渲染有两种方式:
1、On-Screen Rendering(当前屏幕渲染)
指的是GPU的渲染操作是在当前显示的屏幕缓冲区进行。
2、Off-Screen Rendering(离屏渲染)
指的是GPU在当前屏幕缓冲区以外开辟一个缓冲区进行渲染操作。
离屏渲染的代价很高体现在两个方面,1、需要创建一个新的缓冲区。2、上下文切换操作。

会引发离屏渲染的操作:
1、为图层设置遮罩(layer.mask)
2、为图层设置阴影(layer.shadow)
3、为图层设置光栅化(layer.shouldRasterize = true)
4、设置layer.masksToBounds/view.clipsToBounds属性为true
5、使用CGContext在drawRect方法中绘制会耗费更多的内存。

优化方案:
iOS 9.0之前 UIImageView和UIButton设置圆角都会触发离屏渲染。
iOS 9.0之后 UIButton设置圆角会触发离屏渲染,而UIImageView里png图片并不会触发离屏渲染了,如果设置其他阴影效果之类的还是会触发离屏渲染的。

1、UIView(不包括子类)、UILabel、UITextField、UITextView,直接使用layer.cornerRadius 一行代码就行。

2、UIImageView 推荐使用方法二
方法一:使用贝塞尔曲线和CAShapeLayer,生成一个圆角layer,作为视图的layer.mask ,该方法会触发离屏渲染
- (CAShapeLayer *)creatShapLayerBounds:(CGRect)bounds {
UIBezierPath *bezier = [UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:bounds.size.height / 2];
CAShapeLayer *layer = [[CAShapeLayer alloc] init];
layer.frame = bounds;
layer.path = bezier.CGPath;
return layer;
}

方法二:使用贝塞尔曲线绘制路径,并切除多余视图,然后用view重新绘制(drawRect),该方法不会触发离屏渲染,据说会重写drawRect方法会耗费大量内存,本人用xcode测试并未发现。
- (void)drawImageView:(UIImageView *)imageview

{
UIGraphicsBeginImageContextWithOptions(imageview.bounds.size, NO, [UIScreen mainScreen].scale);
[[UIBezierPath bezierPathWithRoundedRect:imageview.bounds cornerRadius:imageview.bounds.size.height] addClip];
[imageview drawRect:view.bounds];
imageview.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}

方法三:使用贝塞尔曲线绘制路径,用CGContext重绘UIImage(drawInRect),该方法也不会触发离屏渲染,但是内存会暴增。

  • (UIImage *)drawRectWithImage:(UIImage *)image
    {
    CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height);
    UIBezierPath *bezier = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:rect.size.height];
    UIGraphicsBeginImageContextWithOptions(rect.size, NO, [UIScreen mainScreen].scale);
    CGContextAddPath(UIGraphicsGetCurrentContext(), bezier.CGPath);
    CGContextClip(UIGraphicsGetCurrentContext());
    [image drawInRect:rect];
    CGContextDrawPath(UIGraphicsGetCurrentContext(), kCGPathFillStroke);
    UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return finalImage;
    }

3、UIButton
1、如果是简单的设置背景色、添加边框,可以使用上面的方法一,用贝塞尔曲线和CAShaplayer,然后将CAShaplayer添加到button的layer层上。
2、如果是设置Image,可以使用上面的方法三,drawInRect重新绘制UIImage。
3、也可以用一个中间透明,四周跟背景色相同的图片贴在button。
4、或者图片直接让UI切好,减少客户端代码量。

3、阴影(shadow)优化
通过设置shadowPath来代替shadowOffset能大幅提高性能。
imageview.layer.shadowColor = [UIColor grayColor].CGColor;
imageview.layer.shadowOpacity = 0;
imageview.layer.shadowRadius = 2.0;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:imageview.frame];
imageview.layer.shadowPath = path.CGPath;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值