圆角

254 阅读3分钟

一般我们在iOS开发的过程中设置圆角都是如下这样设置的。

avatarImageView.clipsToBounds = YES;
[avatarImageView.layer setCornerRadius:50];

这样设置会触发离屏渲染,比较消耗性能。 注意:png图片 UIImageView 处理圆角是不会产生离屏渲染的。(ios9.0之后不会离屏渲染,ios9.0之前还是会离屏渲染)。

1、直接使用setCornerRadius 这种就是最常用的,也是最耗性能的。

2、setCornerRadius 设置圆角之后,shouldRasterize = YES 光栅化

avatarImageView.clipsToBounds = YES;
[avatarImageView.layer setCornerRadius:50];
avatarImageView.layer.shouldRasterize = YES;
avatarImageView.layer.rasterizationScale = [UIScreen mainScreen].scale;  //UIImageView不加这句会产生一点模糊

shouldRasterize = YES 设置光栅化,可以使离屏渲染的结果缓存到内存中存为位图,使用的时候直接使用缓存,节省了一直离屏渲染损耗的性能。

但是如果 layer 及 sublayers 常常改变的话,它就会一直不停的渲染及删除缓。 存重新创建缓存,所以这种情况下建议不要使用光栅化,这样也是比较损耗性能的。

3、直接覆盖一张中间为圆形透明的图片(推荐使用) 这种方法就是多加了一张透明的图片,GPU计算多层的混合渲染 blending 也是会消耗一点性能的,但比第一种方法还是好上很多的。

4、UIImage drawInRect 绘制圆角 这种方式CPU损耗低,内存占用大,而且UIButton上不知道怎么绘制,可以用UIimageView 添加个点击手势当做 UIButton 使用。

UIGraphicsBeginImageContextWithOptions(avatarImageView.bounds.size, NO, [UIScreen mainScreen].scale);
[[UIBezierPath bezierPathWithRoundedRect:avatarImageView.bounds cornerRadius:50] addClip];
[image drawInRect:avatarImageView.bounds];
avatarImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

这段方法可以写在 SDWebImage 的 completed 回调里,在主线程异步绘制。也可以封装到 UIImageView 里,写了个DSRoundImageView。后台线程异步绘制,不会阻塞主线程。

问题:这种方法图片很多的话CPU消耗会高,内存占用也会暴增,而且后台线程绘制会比在主线程绘制占用更多的内存。

5、SDWebImage 处理图片时 Core Graphics 绘制圆角

// UIImage绘制为圆角
int w = imageSize.width;
int h = imageSize.height;
int radius = imageSize.width/2;
UIImage *img = image;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
CGRect rect = CGRectMake(0, 0, w, h);
CGContextBeginPath(context);
addRoundedRectToPath(context, rect, radius, radius);
CGContextClosePath(context);
CGContextClip(context);
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
img = [UIImage imageWithCGImage:imageMasked];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
CGImageRelease(imageMasked);

以上代码我写成了 UIImage 的类别: UIImage+DSRoundImage.h,并在SDWebImage库里处理 image 的时候使用类别方法绘制圆角并缓存。 并在SDWebImage库里处理 image 的时候使用类别方法绘制圆角并缓存。 使用 Instruments 的 Core Animation 查看性能

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

Color Hits Green and Misses Red 如果 shouldRasterize 被设置成YES,对应的渲染结果会被缓存,如果图层是绿色,就表示这些缓存被复用;如果是红色就表示缓存会被重复创建,这就表示该处存在性能问题了。

用Instruments测试得

第一种方法,UIImageView 和 UIButton都高亮为黄色。

第二种方法,UIImageView和UIButton都高亮为绿色

第三种方法,无任何高亮,说明没离屏渲染。

第四种方法无任何高亮,说明没离屏渲染(但是CPU消耗和内存占用会很大)

第五种方法无任何高亮,说明没离屏渲染,而且内存占用也不大。(暂时感觉是最优方法)