老生常谈的圆角图片优化,结合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缓存的应用场景,就可以即插即用啦。

© 著作权归作者所有
这个作品真棒,我要支持一下!
收录我的一些往期文章,以及以后的一些知识点的记录~免费订阅,在技术上共同进步~~
0条评论
top Created with Sketch.