t-io(真的是一个狠牛X的网络通信框架)的创始人给了我灵感,用梓木的照片作素材(PS:哈哈,已经获得受权,特地给我挑了这张让我写博客),正题开始git
- (void)tio_imageUrl:(NSString *)urlStr placeHolderImageName:(NSString *)placeHolderStr radius:(CGFloat)radius { NSURL *url; // 省略 url = [NSURL URLWithString:urlStr]; if (radius != 0.0) { // 有圆角,读取圆角的缓存图片 NSString *cacheurlStr = [urlStr stringByAppendingFormat:@"radius=%.1f",radius]; 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 = [self.image imageWithCornerRadius:radius size:self.frame.size]; self.image = radiusImage; [[SDImageCache sharedImageCache] storeImage:radiusImage forKey:cacheurlStr completion:nil]; //清除原有非圆角图片缓存 [[SDImageCache sharedImageCache] removeImageForKey:urlStr withCompletion:nil]; } }]; } } else { [self sd_setImageWithURL:url placeholderImage:[UIImage imageNamed:placeHolderStr] completed:nil]; } } 复制代码
你们通常不会采起github
imageView.layer.cornerRadius = 20;
imageView.layer.masksToBounds = YES;
复制代码
这样形成离屏渲染,特别是在列表中,当快速滑动列表,生理上的卡顿就会迸发缓存
我使用UIGraphics进行裁剪圆角bash
- (instancetype)imageWithCornerRadius:(CGFloat)cornerRadius size:(CGSize)newSize { UIImage *originImage = self; // 开始裁切圆角 CGRect bounds = CGRectMake(0, 0, newSize.width, newSize.height); UIGraphicsBeginImageContextWithOptions(newSize, NO, UIScreen.mainScreen.scale); CGContextRef context = UIGraphicsGetCurrentContext(); UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:cornerRadius]; CGContextAddPath(context, path.CGPath); CGContextClip(context); [originImage drawInRect:bounds]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } 复制代码
当咱们使用上述方法进行裁切圆角,而后直接给imageView显示,会出现图片变形拉伸或者压缩markdown
可是,有的朋友会采用以下方式,对控件imageView的contentMode进行设置,并裁剪多余的地方网络
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
复制代码
理想很好 现实以下框架
很明显,从“变胖”的梓沐就知道,这段代码并无起什么做用,但这是为何呢??又从何时开始“变胖”的??oop
咱们一步步探寻优化
断点处确定OK,毕竟还没开始切url
梓沐居然变胖了!
“变胖”的问题出在
[originImage drawInRect:bounds];
复制代码
将梓沐原图一个像素不落的所有硬生生的在新的尺寸内绘制,除非原图宽高比与目标尺寸newSize宽高比一致,不然就是压缩或拉伸。
那么等imageView拿到的图片就已是变形的、并且和imageView尺寸同样的图片,因此也没有多余的部分值得clipsToBounds去裁剪,因此contentModel和clipsToBounds无效。
因此咱们须要在裁切圆角前先行作一个处理:转成目标尺寸同比例的图片
scaleImage:方法以下
- (UIImage *)scaleImage:(CGSize)newSize { CGFloat width = self.size.width; CGFloat height = self.size.height; CGFloat scale = newSize.width / newSize.height; CGFloat imageScale = width / height; if (imageScale > scale) { // 以高为准 width = height * scale; } else if (imageScale < scale) { // 以宽为准 height = width / scale; } else { // 正常比例 } // 中心放大 CGRect frame = CGRectMake((self.size.width - width) * 0.5, (self.size.height - height) * 0.5, width, height); CGImageRef imageRef = [self CGImage]; imageRef = CGImageCreateWithImageInRect(imageRef, frame); UIImage *image = [UIImage imageWithCGImage:imageRef]; return image; } 复制代码
***官方吐槽:***这个代码显然是没有优化,那么多判断彻底能够用宏解决,顺便也还能扩展各类contentMode的处理,这个后续会讲,也很简单
处理前
我只实现了UIViewContentModeScaleAspectFill的效果 其余效果作法同样,如上述所说,在scaleImage方法内能够扩展,实现裁剪的居上、居左、居右等,也能够添加上左下右的裁剪偏移量等等
思路都很简单,没有什么特别,工做这么多年,一点点写吧,以前也没养成写博客的习惯
文末小源码:GitHub