UIImageView UIView圆角与性能之间的研究与优化

1,182 阅读3分钟

UIImageView UIView圆角与性能之间的研究与优化

设想:

找出直接设置圆角(maskToBounds/clipsToBounds)帧数下降的例子, 
然后利用Runtime的Method Swizzle交换系统的setClipsToBounds方法 
若设置了layer.cornerRadius 且 clipsToBounds = YES, 则clipsToBounds不会设置为YES, 
而是通过各种其他方法设置圆角, 例如:
1.生成一个圆形的CALayer作为UIImageView.layer.mask.
2.异步剪裁图片.
(以上方法均为网络上流传性能优化方法)

场景:

在日历中每一个UICollectionCell增加一个UIImageView并设置圆角

实际:

图为直接设置cornerRadius和maskToBounds属性, 在如此多的圆角图片下,依然是60帧.
手机iPhone6, 系统为iOS10, 网上传的比较多的是iOS9以上png图片不会触发离屏渲染,
所以不会怎么影响性能, 但我换成jpg图片 依然是60帧.
但我还是尝试了一下上面的两种方法, 看是什么作用:
1.生成一个圆形的CALayer作为UIImageView.layer.mask:
帧数明显降低.

2.异步剪裁图片.
正常操作帧数没有异常, 快速滑动, 会在cell的重用上出问题, 帧数明显下降.

以上肉眼观察明显, 并不需要instrument监控.

所以图片真的没必要异步剪裁!
所以图片真的没必要异步剪裁!
所以图片真的没必要异步剪裁!

UIImageView 结论

在百分之九十九的情况下,
放心使用系统自己的maskToBounds/clipsToBounds与cornerRadius吧,
不会有任何性能问题, 
实际上圆角对于安卓都不是事,
iOS缺老生常谈,确实不应该啊.(基于项目不兼容iOS8了)

UIImageView确定了结果, 
但实际上圆角的设置远不是UIImageView,
怎么对UIView设置圆角并且保持较好的性能,
网上爬文也难有一个比较结论性的回答.
再测试一下直接对UIView直接设置圆角.

场景:

依然是日历, 每一个cell中有2个UILabel.

实际:

这次就出问题了, 滑动帧数直接降到15左右

依然按照上面的思路进行优化, 交换方法为setClipsToBounds与layoutSubViews, 
在设置clipsToBounds = YES且layer.cornerRaius > 0的情况下,
layoutSubViews中进行优化:

1.生成一个圆形的CALayer作为UIImageView.layer.mask:
帧数明显更低了, 所以这种方法在网上流传简直是害人...平均帧数不及10

2.异步剪裁图片.
因为UIView本身并不是UIImage的容器, 所以不太容易直接放, 
新增一个UIImageView盖在上面, 在异步绘制出当前cell, 并放入.
结果喜人, 帧数提高到了60帧附近了.

这里又有之前的前辈教导的常识:CALayer比UIView更轻量, 
所以不需要响应交互的地方用CALayer可以大幅提高性能.
将UIImageView换为CALayer, 并将图片放入contents.
结果实际上并没有更好, 也许是帧数已经快到极限了.

UIView 结论

依然是, 屏幕里圆角数量不多的情况下(15-), 不太需要想办法, 大胆用吧.
屏幕圆角非常多, 可以使用我写的这种方法, 但限制其实也挺多的,
背景色必须是纯色.
当然最好的方法肯定是UI直接把阴影与圆角剪裁给你, 直接用,
虽然会有图层混合运算, 但是其实对性能影响很微妙.

https://github.com/syik/UIImageView-ZJRadius

喜欢的话给个喜欢或者关注一下 3Q~