一般在iOS开发的过程中这样设置圆角
imageView.clipsToBounds = YES;
[imageView.layer setCornerRadius:10];
亲测在TableView 中一屏60个圆角, iOS 9.0 之后FPS能保证58-60,iOS 9.0之前40-60.
代码地址:
以下四种方法
由于没有iOS 8的真机,只能在模拟器上测试,数据可能和真机有出入
- 在iOS 10.3.2 iPhone 6 真机测试,快速滑动 FPS都是60
- 在iOS 8.1 iPhone 6 模拟器测试,快速滑动 FPS 维持在40左右
结论:
-
所以在iOS 9以上系统,基本上没有了离屏渲染,所以直接用CornerRadius和clipsToBounds
-
在iOS 9以下系统,后三种都可以,理论上最后一种CAShapeLayer是属于Core Animation框架的, 是基于GPU的来进行渲染的,性能会好点
-
如果是网络图片的话最好和SDWebImage混合使用,把SDWebImage从网络获取的图片,处理为圆角后保存到本地,避免了多次处理圆角的问题,如果圆角图片一屏在20个以下,基本的不用考虑优化。
1、CornerRadius
imageView.image = [UIImage imageNamed:@"img"];
imageView.image.layer.cornerRadius = 5;
imageView.image.layer.masksToBounds = YES;
会触发离屏渲染,比较消耗性能。
在iOS 模拟器 8.1 版本 FPS也会调到40左右
2、Core Graphics
需要大量计算和增加部分内存
- (instancetype)circleImage
{
UIGraphicsBeginImageContextWithOptions(self.size, NO, [UIScreen mainScreen].scale);
[[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, self.size.width, self.size.height)
cornerRadius:self.size.width / 2.0] addClip];
[self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
3、Blended
此方法就是在要添加圆角的视图上再叠加一个部分透明的视图,只对圆角部分进行遮挡。图层混合的透明度处理方式与mask正好相反。此方法虽然是最优解,没有离屏渲染,没有额外的CPU计算,但是应用范围有限。
@implementation TYRoundImageView
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
UIImageView *_cornerCoverImage = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
[_cornerCoverImage setImage:[UIImage imageNamed:@"app_imageCornerCover"]];
[self addSubview:_cornerCoverImage];
}
return self;
}
@end
4、UIBezierPath CAShapeLayer
CAShapeLayer是基于贝塞尔曲线而存在的, 如果没有贝塞尔曲线提供路径来画出图形, CAShapeLayer就没有存在的意义, CAShapeLayer可以使得不用在drawRect:方法中实现画图.
另外, CAShapeLayer是属于CoreAnimation框架的, 是基于GPU的来进行渲染的, 不比使用CoreGraphic框架, 是基于CPU来渲染的, 所以CAShapeLayer效率相对比较高一些
- (void)circleViewWithView:(UIView *)view {
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:view.bounds.size];
CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];
maskLayer.frame = view.bounds;
maskLayer.path = maskPath.CGPath;
view.layer.mask = maskLayer;
}
Off-Screen Rendering
离屏渲染,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。
为什么离屏这么耗时?
- 原因主要有创建缓冲区和上下文切换。创建新的缓冲区代价都不算大,付出最大代价的是上下文切换。
上下文切换
上下文切换,不管是在GPU渲染过程中,还是一直所熟悉的进程切换,上下文切换在哪里都是一个相当耗时的操作。首先我要保存当前屏幕渲染环境,然后切换到一个新的绘制环境,申请绘制资源,初始化环境,然后开始一个绘制,绘制完毕后销毁这个绘制环境,如需要切换到On-Screen Rendering或者再开始一个新的离屏渲染重复之前的操作。 下图描述了一次mask的渲染操作。
image.png一次mask发生了两次离屏渲染和一次主屏渲染
网友评论