iOS图片圆角设置汇总

2017-12-15  本文已影响38人  张聪_2048

点击下载 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

上一篇下一篇

猜你喜欢

热点阅读