iOS 离屏渲染的研究(三)-------图片设置圆角性能问题

demo下载ios

通常咱们在iOS开发的过程当中设置圆角都是以下这样设置的。
git

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

 这样设置会触发离屏渲染,比较消耗性能。好比当一个页面上有十几头像这样设置了圆角
 会明显感受到卡顿。

 注意:png图片UIImageView处理圆角是不会产生离屏渲染的。(ios9.0以后不会离屏渲染,ios9.0以前仍是会离屏渲染)。
全部若是要高性能的设置圆角就须要找另外的方法了。下面是我找到的一些方法并写了一个例子。



设置圆角的方法
github

(1)直接使用setCornerRadius缓存

这种就是最经常使用的,也是最耗性能的。
(2) setCornerRadius设置圆角以后,shouldRasterize=YES光栅化

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

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

可是若是layer及sublayers经常改变的话,它就会一直不停的渲染及删除缓存从新
建立缓存,因此这种状况下建议不要使用光栅化,这样也是比较损耗性能的。
(3) 直接覆盖一张中间为圆形透明的图片(推荐使用)

这种方法就是多加了一张透明的图片,GPU计算多层的混合渲染blending也是会消耗
一点性能的,但比第一种方法仍是好上不少的。
(4) UIImage drawInRect绘制圆角

这种方式GPU损耗低内存占用大,并且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。后台线程异步绘制,不会阻塞主线程。
问题:这种方法图片不少的话CUP消耗会高,内存占用也会暴增,并且后台线程绘制会比在主线程绘制占用更多的内存,不知道怎么解决?求大神指教!

(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的时候使用类别方法绘制圆角并缓存。性能


使用Instruments的Core Animation查看性能测试

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

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

用Instruments测试线程

第(1)种方法,UIImageView和UIButton都高亮为黄色。

第(2)种方法,UIImageView和UIButton都高亮为绿色
第(3)种方法,无任何高亮,说明没离屏渲染。
这种圆片覆盖的方法通常只用在底色为纯色的时候,若是圆角图片的父View是张图片的时候就没办法了,并且底色若是是多种颜色的话那要作多张不一样颜色的圆片覆盖。(能够用代码取底色的颜色值给圆片着色)
第(4)种方法无任何高亮,说明没离屏渲染(可是CPU消耗和内存占用会很大)
第(5)种方法无任何高亮,说明没离屏渲染,并且内存占用也不大。(暂时感受是最优方法)


 参考:http://www.jianshu.com/p/34189f62bfd8
相关文章
相关标签/搜索