圆角这东西被无数性能追求者津津乐道,无数小白们高山仰止。 至于圆角的几种实现方案,设置cornerRadius、加maskLayer、直接加镂空图、内存异步裁剪等等,网络上一搜一大把,这里就不再重复了。这里有两点要提醒下,纹理裁剪才是off-screen rendering的原因,而不是设置圆角。当然你要是作死的去设了layer的fillColor,再来设圆角,那就只能说no zuo no die ;另外在使用光栅化时,一定要设置scale以适配屏幕分辨率。
既然标哥都给出开源方案了,那就比较一下,检查下自己的不足吧。为参照相同的运行条件,笔者把自己写的辅助类放到标哥的Demo里,实现相同的效果。然后从设计思路、外观呈现、CPU和内存、帧速、代码量、侵入性和易用性、适用场景等多个方面做出比较。
标哥的开源库:https://github.com/CoderJackyHuang/HYBImageCliped
笔者fork后修改的项目:https://github.com/1962449521/HYBImageCliped
该功能类的在线维护:https://github.com/1962449521/WHUCornerMaker
笔者整理中的辅助类集:https://github.com/1962449521/WHUKit/tree/master/WHUKitDemo/WHUKitDemo/WHUKit
以下为笔者方案与标哥开源库的比较
一、 突破口的选择
标哥选择的起点是内存中剪裁图片,通过缓存策略以优化性能,给UIView、UIImageView、UIButton等控件增加Category以扩展功能。笔者选择的起点是绘制镂空图,同样使用了缓存以提高复用。因为长期开发SDK尽量不使用Category的习惯,笔者采用辅助类的形式提供功能实现。
二、 功能及解决问题
主要的出发点都是为了解决圆角图片离屏渲染影响滑动帧速的问题。标哥采用了剪裁图片的方式,能够适应背景非单色情况;在控件内部的图片,能提供圆角效果,比如按钮内非抵边的image;在边线的绘制上,提供了形状边框,边框有填充和边线。笔者提供的辅助类只适用背景单色,裁剪针对UIView或其子类整体,边线只提供单线。
三、 外观呈现
除了双色边线外,其它的外观都能做到相同的效果。
标哥静态容器 | 笔者静态容器 |
标哥collectionView | 笔者collectionView |
四、CPU和内存
标哥方案CPU使用骤增,最高达到82%。内存使用也高于笔者。因为笔者采用了每次cell出现时重绘边角,所以CPU略高。如果确定每次cell重用时边角位置正确,可以不重绘边角,CPU能稳定在13%左右。图片相对较少,内存使用差别不明显。当不同图片较多时,标哥使用方案需大量缓存裁切好的图片,猜测会在内存使用上随之增加。而笔者方案会复用相同角度颜色的边角,图片增多时不会增加圆角图片的内存开销。
标哥方案 |
笔者方案 |
五、 帧速
滑动帧速基本相近,都有较好的体验,笔者方案数值相对较高。
标哥方案 |
笔者方案 |
六、代码量
标哥使用了一个管理类HYBImageClipedManager,以及提供了UIImage、UIView、UIButton三个类的category,总共约1千行代码。笔者提供了WHUCornerMaker、WHUBorderMaker两个辅助功能类,约250行代码。
七、侵入性和易用性
以下为笔者两个辅助类的头文件声明和暴露的使用API,自认为还是较为清晰易用的。这里要说到关于注释,多余的注释是违反DRY原则的,不过由于国人对英文的理解不直接或者项目编码约定,而加了许多不必要的注释。还是应当以清晰符合语义的方法、变量命名作为首选。至于标哥提供的接入设计,方法太多就不在这里列出了,感兴趣的童鞋可以从本文提供的链接跳入查看^^
@interface WHUCornerMaker : NSObject + (BOOL) isCorneredAtView:(UIView * _Nonnull)view; // 优先选取view 沿superview上的父类容器的背景色, 如果一直为nil, 则取defaultColor 作为圆角颜色 - (void) roundView:( UIView * _Nonnull ) view withCornerRadius:(CGFloat) radius defaultColor:( UIColor * _Nullable)color; - (void) roundViews:(NSArray<UIView *> * _Nonnull) views withCornerRadius:(CGFloat) radius defaultColor:( UIColor * _Nullable)color; - (void) roundView:(UIView * _Nonnull) view withCornerRadius:(CGFloat) radius defaultColor:( UIColor * _Nullable)color byRoundingCorners:(UIRectCorner)corners; - (void) roundViews:(NSArray<UIView *> * _Nonnull) views withCornerRadius:(CGFloat) radius defaultColor:( UIColor * _Nullable)color byRoundingCorners:(UIRectCorner)corners; @end
@interface WHUBorderMaker : NSObject + (void) borderView:( UIView * _Nonnull ) view withCornerRadius:(CGFloat) radius width:(CGFloat)borderWidth color:(UIColor * _Nonnull)borderColor; + (void) borderView:( UIView * _Nonnull ) view withCornerRadius:(CGFloat) radius width:(CGFloat)borderWidth color:(UIColor * _Nonnull)borderColor byRoundingCorners:(UIRectCorner)corners; @end
八、适用场景
不可否认,标哥提供了更多功能,比如拿到裁切的图片,绘制双色边框等。不过这样的使用场景应该是较少的,笔者提供了辅助类能满足大多数场景的需求。
九、总结
在做通用性开源库的时候,可能会考虑更多的东西。但花80%的精力去实现5%使用者的需求是否有必要是有待斟酌的。在笔者方案和标哥方案的比较中,总体而言笔者的方案性能是高出很多,并不随使用条件复杂性的增加而性能降低。这一方面是内存裁剪图片本就是骑虎难下的选择,一方面也是笔者只针对有限的使用场景和需求。