美文网首页
iOS图片圆角设置汇总

iOS图片圆角设置汇总

作者: 张聪_2048 | 来源:发表于2017-12-15 13:43 被阅读38次

    点击下载 Demo

    一、CornerRadius 设置圆角

    如果仅仅是view需要设置圆角,是不要设置maskToBounds的,并且someView.layer.cornerRadius并不会触发离屏渲染(Off-Screen Rendering)。当界面中有其他的包含子控件的view,如label,imageView等,需要设置圆角,但是数量并不多。此时可以安心的使用如下的方法,这里虽然会触发离屏渲染,但是由于数量比较少,所以对全局的影响一般不会很大。

    self.iconView.layer.cornerRadius = self.iconView.frame.size.height / 2;
    self.iconView.layer.masksToBounds = YES;
    

    离屏渲染(Off-Screen Rendering):指的是 GPU(图形处理器)在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。离屏渲染耗时是发生在离屏这个动作上面,而不是渲染。为什么离屏这么耗时?原因主要有创建缓冲区和上下文切换。创建新的缓冲区代价都不算大,付出最大代价的是上下文切换。

    上下文切换:不管是在 GPU 渲染过程中,还是一直所熟悉的进程切换,上下文切换在哪里都是一个相当耗时的操作。首先我要保存当前屏幕渲染环境,然后切换到一个新的绘制环境,申请绘制资源,初始化环境,然后开始一个绘制,绘制完毕后销毁这个绘制环境,如需要切换到On-Screen Rendering或者再开始一个新的离屏渲染重复之前的操作。

    注意:ios9.0之后对UIImageView的圆角设置做了优化,UIImageView这样设置圆角不会触发离屏渲染,ios9.0之前还是会触发离屏渲染。而UIButton还是都会触发离屏渲染。

    二、Core Graphics 生成圆角图片

    使用 Graphics 绘制新的图片,需要大量计算和增加部分内存

    - (UIImage *)radiusImageWithImage:(UIImage *)image withRadius:(CGFloat)radius {
        UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);
        CGRect roundRect = CGRectMake(0, 0, image.size.width, image.size.height);
        if (!radius) {
            radius = image.size.width / 2.0;
        }
        [[UIBezierPath bezierPathWithRoundedRect:roundRect
                                    cornerRadius:radius] addClip];
        [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
        
        UIImage *radiusImg = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return radiusImg;
    }
    

    三、UIBezierPath CAShapeLayer

    使用CAShapeLayer来切割视图控件。CAShapeLayer是基于贝塞尔曲线而存在的, 如果没有贝塞尔曲线提供路径来画出图形, CAShapeLayer就没有存在的意义, CAShapeLayer可以使得不用在drawRect:方法中实现画图。另外, CAShapeLayer是属于CoreAnimation框架的, 是基于GPU的来进行渲染的, 不比使用CoreGraphic框架, 是基于CPU来渲染的, 所以CAShapeLayer效率相对比较高一些

    - (void)circleViewWithView:(UIView *)view radius:(CGFloat)radius {
        UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:view.bounds
                                                            cornerRadius:radius];
        CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init];
        maskLayer.frame = view.bounds;
        maskLayer.path = maskPath.CGPath;
        view.layer.mask = maskLayer;
    }
    

    四、覆盖镂空图片

    此方法就是在要添加圆角的视图上再叠加一个部分透明的视图,只对圆角部分进行遮挡。图层混合的透明度处理方式与mask正好相反。此方法虽然是最优解,没有离屏渲染,没有额外的CPU计算,但是应用范围有限。

    - (void)method4 {
        UIImageView *iconCover= [[UIImageView alloc] initWithFrame:self.iconView.frame];
        iconCover.image = [UIImage imageNamed:@"imageCornerCover"];
        [self addSubview:iconCover];
        
        UIImageView *imgCover = [[UIImageView alloc] initWithFrame:self.imgView.frame];
        imgCover.image = [UIImage imageNamed:@"imageCornerCover"];
        [self addSubview:imgCover];
    }
    

    五、SDWebImage + Graphics

    使用 Graphics 切图,和 SDWebImage 相结合,把 Graphics 切图的耗时操作放在子线程处理,处理完使用 SDWebImage 存储,然后再给控件赋值。

    - (void)circleImageWithUrl:(NSURL *)imgUrl
                   placeholder:(UIImage *)placeholder
                          rate:(CGFloat)rate {
        NSString *imgkey = [self keyWithImageUrl:imgUrl];
        UIImage *circleImg = [[SDImageCache sharedImageCache] imageFromCacheForKey:imgkey];
        if (circleImg) {
            self.image = circleImg;
            return;
        }
        
        if (self.loadingImageUrlStr) {
            // 取消上一个图片绘制
            [self.cancelLoadingArr addObject:self.loadingImageUrlStr];
        }
        
        __weak typeof(self)wkSlef = self;
        [self sd_setImageWithURL:imgUrl
                placeholderImage:placeholder
                         options:SDWebImageRetryFailed | SDWebImageAvoidAutoSetImage
                       completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
                           [wkSlef backgroundDrawImageForImage:image
                                                cacheWithUrl:imageURL
                                                        rate:rate];
                       }];
    }
    
    - (void)backgroundDrawImageForImage:(UIImage *)image
                           cacheWithUrl:(NSURL *)imgUrl
                                   rate:(CGFloat)rate {
        [self setLoadingImageUrlStr:imgUrl.absoluteString];
        
        __weak typeof(self)wkSlef = self;
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
            
            UIGraphicsBeginImageContextWithOptions(image.size, NO, [UIScreen mainScreen].scale);
            CGRect roundRect = CGRectMake(0, 0, image.size.width, image.size.height);
            CGFloat radius = image.size.width * rate;
            [[UIBezierPath bezierPathWithRoundedRect:roundRect
                                        cornerRadius:radius] addClip];
            [image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
            
            UIImage *radiusImg = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            
            dispatch_async(dispatch_get_main_queue(), ^{
                [[SDImageCache sharedImageCache] storeImage:radiusImg
                                                     forKey:[wkSlef keyWithImageUrl:imgUrl]
                                                 completion:nil];
                if ([wkSlef.cancelLoadingArr containsObject:imgUrl.absoluteString]) {
                    [wkSlef.cancelLoadingArr removeObject:imgUrl.absoluteString];
                } else {
                    wkSlef.image = radiusImg;
                }
            });
        });
    }
    



    下载Demo:https://github.com/ZhangJingHao/ZJHCornerImage
    参考链接:http://www.jianshu.com/p/8c89460fc676

    相关文章

      网友评论

          本文标题:iOS图片圆角设置汇总

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