iOS图片圆角优化-第三方工具源码解读

图片圆角优化工具的概述

该库是通过UIImageView写一个分类,调用一行代码实现圆角的优化:imageview.aliCornerRadius = 5.0f,核心思想就是使用圆角图片替换系统圆角

核心技术点
  • KVO观察者模式的使用
@interface HJImageObserver : NSObject

@property (nonatomic, assign) UIImageView *originImageView;
@property (nonatomic, strong) UIImage *originImage;
@property (nonatomic, assign) CGFloat cornerRadius;

- (instancetype)initWithImageView:(UIImageView *)imageView;

@end

@implementation HJImageObserver

- (void)dealloc {
    [self.originImageView removeObserver:self forKeyPath:@"image"];
    [self.originImageView removeObserver:self forKeyPath:@"contentMode"];
}

- (instancetype)initWithImageView:(UIImageView *)imageView{
    if (self = [super init]) {
        self.originImageView = imageView;
        [imageView addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:nil];
        [imageView addObserver:self forKeyPath:@"contentMode" options:NSKeyValueObservingOptionNew context:nil];
    }
    return self;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString*, id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"image"]) {
        UIImage *newImage = change[@"new"];
        if (![newImage isKindOfClass:[UIImage class]] || newImage.aliCornerRadius) {
            return;
        }
        [self updateImageView];
    }
    if ([keyPath isEqualToString:@"contentMode"]) {
        self.originImageView.image = self.originImage;
    }
}

通过创建动态属性观察者HJImageObserver,监听imagecontentMode属性,当image变化时,能够触发圆角图片的生成,从而达到自动实现圆角图片替换的目的

  • 截图渲染代码
- (void)updateImageView {
    self.originImage = self.originImageView.image;
    if (!self.originImage) {
        return;
    }
    UIImage *image = nil;
    UIGraphicsBeginImageContextWithOptions(self.originImageView.bounds.size, NO, [UIScreen mainScreen].scale);
    CGContextRef currnetContext = UIGraphicsGetCurrentContext();
    if (currnetContext) {
        CGContextAddPath(currnetContext, [UIBezierPath bezierPathWithRoundedRect:self.originImageView.bounds cornerRadius:self.cornerRadius].CGPath);
        CGContextClip(currnetContext);
        [self.originImageView.layer renderInContext:currnetContext];
        image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    }
    
    if ([image isKindOfClass:[UIImage class]]) {
        image.aliCornerRadius = YES;
        self.originImageView.image = image;
    } else {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateImageView];
        });
    }
}

这段代码不是直接渲染原始Image对象,而是先截取UIImageView视图Layer生成的Image,然后再做渲染。原因很简单,因为UIImageView呈现方式涉及多种ContentMode,通过渲染UIImageView视图Layer生成的图片可以巧妙的解决UIImageView显示模式的问题。
此外,由于系统原因,对于像UITableViewCell的UIImageView,第一次创建赋图时,可能无法获取UIImageView视图Layer的图片,此时,可以通过切换异步RunLoop达到延时渲染的目的

  • 分类添加属性代码巧用
@interface UIImage (cornerRadius)

@property (nonatomic, assign) BOOL aliCornerRadius;

@end

@implementation UIImage (cornerRadius)

- (BOOL)aliCornerRadius {
    return [objc_getAssociatedObject(self, @selector(aliCornerRadius)) boolValue];
}

- (void)setAliCornerRadius:(BOOL)aliCornerRadius {
    objc_setAssociatedObject(self, @selector(aliCornerRadius), @(aliCornerRadius), OBJC_ASSOCIATION_COPY_NONATOMIC);
}

@end

在setAliCornerRadius:方法中使用了一个objc_setAssociatedObject的方法,这个方法有四个参数,分别是:源对象,关联时用来标记是哪一个属性的key(因为你可能要添加很多属性),关联的对象和一个关联策略,这里我们可以看出一大亮点,就是关联的key值所用的写法,一般属性的key我们会这样写:

//利用静态变量地址唯一不变的特性
1、static void *strKey = &strKey;
2、static NSString *strKey = @"strKey";
3、static char strKey;

1)但是这段代码里的keySelector作为key。在我们需要创建出许多的分类属性时,以上述的方式定义出许多的static const keys无疑是比较繁琐的事情,还好有个方法可以避免繁琐事件:
我们为关联对象所使用的参数key是一个类型static const void *的指针。Objective-C中的selector其实质上也是一个常量指针,这意味着它们很适合作为关联对象的key值。假如你用关联对象的方式去实现一个属性,你可以使用这个属性的getter方法的方法名作为这个key
2) 这里我们还可以使用_cmd简化下代码,_cmdObjective-C的方法中表示当前方法的selector,所以我们简化下get方法的写法:

- (BOOL)aliCornerRadius{
    return [objc_getAssociatedObject(self, _cmd) boolValue];
}

源码链接,点这里哦~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值