老生常谈的圆角图片优化,结合SDWebImage的解决方案。

很早就想写一篇讲述圆角优化的博客了。。结果发现这篇文章iOS 高效添加圆角效果实战讲解写得很好:摘录文章的总结部分,当拓展阅读了:

总结
如果能够只用 cornerRadius 解决问题,就不用优化。
如果必须设置 masksToBounds,可以参考圆角视图的数量,如果数量较少(一页只有几个)也可以考虑不用优化。
UIImageView 的圆角通过直接截取图片实现,其它视图的圆角可以通过 Core Graphics 画出圆角矩形实现。

过早的优化是恶魔,这句话确实很有道理

Premature optimization is the root of all evil --Donald Knuth

当时我做圆角优化的场景,是一个collectionView很多头像的展示。如果单纯的用layer设置cornerRadius和masksToBounds,会产生离屏渲染,小心别让圆角成了你列表的帧数杀手,这篇文章已经写的很清楚了,就不赘述了。

self.xxView.layer.cornerRadius = 5.0f;
self.xxView.layer.masksToBounds = YES;

Advanced Graphics and Animations for iOS Apps(session 419) 学习与延伸这篇文章也介绍了离屏渲染的一些知识,有需要的同学可以去拓展阅读一下。

正文

其实写到这里我已经很方了。。因为感觉好多人都写过了。。
这边再留两篇文章:
最早接触到圆角优化是里脊串写的一次对MKMapView的性能优化
近来还有叶孤城___reviewcode.cn里提出的解决方案。
你们可以先看我的文章,然后再去拓展阅读,反正上面那么多链接你们也要看一会[认真脸]。

既然原理上面的文章都讲过很多了,我真不好意思再讲一遍了,我就来说说我怎么做的吧。
首先给imageView一个catagory,核心方法如下:

- (void)lhy_loadImageUrlStr:(NSString *)urlStr placeHolderImageName:(NSString *)placeHolderStr radius:(CGFloat)radius;

当然也有些简便的方法方便不同场景调用:

- (void)lhy_loadImageUrlStr:(NSString *)urlStr;
- (void)lhy_loadImageUrlStr:(NSString *)urlStr radius:(CGFloat)radius;

核心方法是这样写的:

- (void)lhy_loadImageUrlStr:(NSString *)urlStr placeHolderImageName:(NSString *)placeHolderStr radius:(CGFloat)radius {
    //something
    //这里有针对不同需求的处理,我就没贴出来了
    //...

    NSURL *url;

    if (placeHolderStr == nil) {
        placeHolderStr = @"你通用的占位图地址";
    }
   
    //这里传CGFLOAT_MIN,就是默认以图片宽度的一半为圆角
    if (radius == CGFLOAT_MIN) {
        radius = self.frame.size.width/2.0;
    }

    url = [NSURL URLWithString:urlStr];

    if (radius != 0.0) {
        //头像需要手动缓存处理成圆角的图片
        NSString *cacheurlStr = [urlStr stringByAppendingString:@"radiusCache"];
        UIImage *cacheImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:cacheurlStr];
        if (cacheImage) {
            self.image = cacheImage;
        }
        else {
            [self sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:placeHolderStr] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                if (!error) {
                    UIImage *radiusImage = [UIImage createRoundedRectImage:image size:self.frame.size radius:radius];
                    self.image = radiusImage;
                    [[SDImageCache sharedImageCache] storeImage:radiusImage forKey:cacheurlStr];
                    //清除原有非圆角图片缓存
                    [[SDImageCache sharedImageCache] removeImageForKey:urlStr];
                }
            }];
        }
    }
    else {
        [self sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:placeHolderStr] completed:nil];
    }
}

圆角的绘制方法是一个imageView的catagory

static void addRoundedRectToPath(CGContextRef context, CGRect rect, float ovalWidth,
                                 float ovalHeight)
{
    float fw, fh;
    
    if (ovalWidth == 0 || ovalHeight == 0)
    {
        CGContextAddRect(context, rect);
        return;
    }
    
    CGContextSaveGState(context);
    CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
    CGContextScaleCTM(context, ovalWidth, ovalHeight);
    fw = CGRectGetWidth(rect) / ovalWidth;
    fh = CGRectGetHeight(rect) / ovalHeight;
    
    //根据圆角路径绘制
    CGContextMoveToPoint(context, fw, fh/2); 
    CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1); 
    CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1); 
    CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1); 
    CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
    
    CGContextClosePath(context);
    CGContextRestoreGState(context);
}

+ (id)createRoundedRectImage:(UIImage*)image size:(CGSize)size radius:(NSInteger)r
{
    int w = size.width;
    int h = size.height;
    
    UIImage *img = image;
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedFirst);
    //CGContextRef context = UIGraphicsGetCurrentContext();
    CGRect rect = CGRectMake(0, 0, w, h);
    
    CGContextBeginPath(context);
    addRoundedRectToPath(context, rect, r, r);
    CGContextClosePath(context);
    CGContextClip(context);
    CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
    CGImageRef imageMasked = CGBitmapContextCreateImage(context);
    img = [UIImage imageWithCGImage:imageMasked];
    
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);
    CGImageRelease(imageMasked);
    
    return img;
}

这样只要两个catagory,这个头像圆角结合SDWebImage缓存的应用场景,就可以即插即用啦。

简书已经弃用,欢迎移步我的小专栏:
https://xiaozhuanlan.com/dahuihuiiOS

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看...
    F麦子阅读 5,143评论 5 13
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看...
    每天刷两次牙阅读 8,572评论 6 30
  • 因为我希望我的人生有更多可能。 因为当初不想工作,所以毕业后慌忙之下随便进了一家公司。这家公司呢工资一般,环境放松...
    四一三阅读 798评论 5 3
  • 看了病魔缠身好几集,最大的感触就是,当开始出现症状时,人们总是用习惯以往的经验来判断,觉得不过是一次普通感冒或...
    菩树阅读 128评论 0 0
  • 2015.12.24 今天可是平安夜啊 说过我不爱过洋节 可能是心里有一种说不出的爱国情愫 觉得我要为保护中国的传...
    麻绳兮冻阅读 418评论 1 0