美文网首页
iOS 圆角问题

iOS 圆角问题

作者: iOS104 | 来源:发表于2017-07-03 19:20 被阅读169次

    一般在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发生了两次离屏渲染和一次主屏渲染

    相关文章

      网友评论

          本文标题:iOS 圆角问题

          本文链接:https://www.haomeiwen.com/subject/ocyzcxtx.html