249 lines
8.1 KiB
Objective-C
249 lines
8.1 KiB
Objective-C
//
|
|
// UIImageView+CornerRadius.m
|
|
// MyPractise
|
|
//
|
|
|
|
#import "UIImageView+CornerRadius.h"
|
|
#import <objc/runtime.h>
|
|
|
|
const char kRadius;
|
|
const char kRoundingCorners;
|
|
const char kIsRounding;
|
|
const char kHadAddObserver;
|
|
const char kProcessedImage;
|
|
|
|
const char kBorderWidth;
|
|
const char kBorderColor;
|
|
|
|
@interface UIImageView ()
|
|
|
|
@property (assign, nonatomic) CGFloat radius;
|
|
@property (assign, nonatomic) UIRectCorner roundingCorners;
|
|
@property (assign, nonatomic) CGFloat borderWidth;
|
|
@property (strong, nonatomic) UIColor *borderColor;
|
|
@property (assign, nonatomic) BOOL hadAddObserver;
|
|
@property (assign, nonatomic) BOOL isRounding;
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
|
|
@implementation UIImageView (CornerRadius)
|
|
|
|
/**
|
|
* @brief init the Rounding UIImageView, no off-screen-rendered
|
|
*/
|
|
- (instancetype)initWithRoundingRectImageView {
|
|
self = [super init];
|
|
if (self) {
|
|
[self zy_cornerRadiusRoundingRect];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
/**
|
|
* @brief init the UIImageView with cornerRadius, no off-screen-rendered
|
|
*/
|
|
- (instancetype)initWithCornerRadiusAdvance:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType {
|
|
self = [super init];
|
|
if (self) {
|
|
[self zy_cornerRadiusAdvance:cornerRadius rectCornerType:rectCornerType];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
/**
|
|
* @brief attach border for UIImageView with width & color
|
|
*/
|
|
- (void)zy_attachBorderWidth:(CGFloat)width color:(UIColor *)color {
|
|
self.borderWidth = width;
|
|
self.borderColor = color;
|
|
}
|
|
|
|
#pragma mark - Kernel
|
|
/**
|
|
* @brief clip the cornerRadius with image, UIImageView must be setFrame before, no off-screen-rendered
|
|
*/
|
|
- (void)zy_cornerRadiusWithImage:(UIImage *)image cornerRadius:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType {
|
|
CGSize size = self.bounds.size;
|
|
CGFloat scale = [UIScreen mainScreen].scale;
|
|
CGSize cornerRadii = CGSizeMake(cornerRadius, cornerRadius);
|
|
|
|
UIGraphicsBeginImageContextWithOptions(size, NO, scale);
|
|
if (nil == UIGraphicsGetCurrentContext()) {
|
|
return;
|
|
}
|
|
UIBezierPath *cornerPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:rectCornerType cornerRadii:cornerRadii];
|
|
[cornerPath addClip];
|
|
[image drawInRect:self.bounds];
|
|
[self drawBorder:cornerPath];
|
|
UIImage *processedImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
objc_setAssociatedObject(processedImage, &kProcessedImage, @(1), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
self.image = processedImage;
|
|
}
|
|
|
|
/**
|
|
* @brief clip the cornerRadius with image, draw the backgroundColor you want, UIImageView must be setFrame before, no off-screen-rendered, no Color Blended layers
|
|
*/
|
|
- (void)zy_cornerRadiusWithImage:(UIImage *)image cornerRadius:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType backgroundColor:(UIColor *)backgroundColor {
|
|
CGSize size = self.bounds.size;
|
|
CGFloat scale = [UIScreen mainScreen].scale;
|
|
CGSize cornerRadii = CGSizeMake(cornerRadius, cornerRadius);
|
|
|
|
UIGraphicsBeginImageContextWithOptions(size, YES, scale);
|
|
if (nil == UIGraphicsGetCurrentContext()) {
|
|
return;
|
|
}
|
|
UIBezierPath *cornerPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:rectCornerType cornerRadii:cornerRadii];
|
|
UIBezierPath *backgroundRect = [UIBezierPath bezierPathWithRect:self.bounds];
|
|
[backgroundColor setFill];
|
|
[backgroundRect fill];
|
|
[cornerPath addClip];
|
|
[image drawInRect:self.bounds];
|
|
[self drawBorder:cornerPath];
|
|
UIImage *processedImage = UIGraphicsGetImageFromCurrentImageContext();
|
|
UIGraphicsEndImageContext();
|
|
objc_setAssociatedObject(processedImage, &kProcessedImage, @(1), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
self.image = processedImage;
|
|
}
|
|
|
|
/**
|
|
* @brief set cornerRadius for UIImageView, no off-screen-rendered
|
|
*/
|
|
- (void)zy_cornerRadiusAdvance:(CGFloat)cornerRadius rectCornerType:(UIRectCorner)rectCornerType {
|
|
self.radius = cornerRadius;
|
|
self.roundingCorners = rectCornerType;
|
|
self.isRounding = NO;
|
|
|
|
if (!self.hadAddObserver) {
|
|
[self addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:nil];
|
|
self.hadAddObserver = YES;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief become Rounding UIImageView, no off-screen-rendered
|
|
*/
|
|
- (void)zy_cornerRadiusRoundingRect {
|
|
self.isRounding = YES;
|
|
|
|
if (!self.hadAddObserver) {
|
|
[self addObserver:self forKeyPath:@"image" options:NSKeyValueObservingOptionNew context:nil];
|
|
self.hadAddObserver = YES;
|
|
}
|
|
}
|
|
|
|
#pragma mark - Private
|
|
- (void)drawBorder:(UIBezierPath *)path {
|
|
if (0 != self.borderWidth && nil != self.borderColor) {
|
|
[path setLineWidth:2 * self.borderWidth];
|
|
[self.borderColor setStroke];
|
|
[path stroke];
|
|
}
|
|
}
|
|
|
|
- (void)dealloc {
|
|
if (self.hadAddObserver) {
|
|
[self removeObserver:self forKeyPath:@"image"];
|
|
}
|
|
}
|
|
|
|
- (void)validateFrame {
|
|
if (self.frame.size.width == 0) {
|
|
[self.class swizzleMethod:@selector(layoutSubviews) anotherMethod:@selector(zy_LayoutSubviews)];
|
|
}
|
|
}
|
|
|
|
+ (void)swizzleMethod:(SEL)oneSel anotherMethod:(SEL)anotherSel {
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
Method oneMethod = class_getInstanceMethod(self, oneSel);
|
|
Method anotherMethod = class_getInstanceMethod(self, anotherSel);
|
|
|
|
method_exchangeImplementations(oneMethod, anotherMethod);
|
|
});
|
|
}
|
|
|
|
- (void)zy_LayoutSubviews {
|
|
[super layoutSubviews];
|
|
if (self.isRounding) {
|
|
[self zy_cornerRadiusWithImage:self.image cornerRadius:self.frame.size.width/2 rectCornerType:UIRectCornerAllCorners];
|
|
} else if (0 != self.radius && 0 != self.roundingCorners && nil != self.image) {
|
|
[self zy_cornerRadiusWithImage:self.image cornerRadius:self.radius rectCornerType:self.roundingCorners];
|
|
}
|
|
}
|
|
|
|
#pragma mark - KVO for .image
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
|
|
if ([keyPath isEqualToString:@"image"]) {
|
|
UIImage *newImage = change[NSKeyValueChangeNewKey];
|
|
if ([newImage isMemberOfClass:[NSNull class]]) {
|
|
return;
|
|
} else if ([objc_getAssociatedObject(newImage, &kProcessedImage) intValue] == 1) {
|
|
return;
|
|
}
|
|
[self validateFrame];
|
|
if (self.isRounding) {
|
|
[self zy_cornerRadiusWithImage:newImage cornerRadius:self.frame.size.width/2 rectCornerType:UIRectCornerAllCorners];
|
|
} else if (0 != self.radius && 0 != self.roundingCorners && nil != self.image) {
|
|
[self zy_cornerRadiusWithImage:newImage cornerRadius:self.radius rectCornerType:self.roundingCorners];
|
|
}
|
|
}
|
|
}
|
|
|
|
#pragma mark property
|
|
- (CGFloat)borderWidth {
|
|
return [objc_getAssociatedObject(self, &kBorderWidth) floatValue];
|
|
}
|
|
|
|
- (void)setBorderWidth:(CGFloat)borderWidth {
|
|
objc_setAssociatedObject(self, &kBorderWidth, @(borderWidth), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
}
|
|
|
|
- (UIColor *)borderColor {
|
|
return objc_getAssociatedObject(self, &kBorderColor);
|
|
}
|
|
|
|
- (void)setBorderColor:(UIColor *)borderColor {
|
|
objc_setAssociatedObject(self, &kBorderColor, borderColor, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
}
|
|
|
|
- (BOOL)hadAddObserver {
|
|
return [objc_getAssociatedObject(self, &kHadAddObserver) boolValue];
|
|
}
|
|
|
|
- (void)setHadAddObserver:(BOOL)hadAddObserver {
|
|
objc_setAssociatedObject(self, &kHadAddObserver, @(hadAddObserver), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
}
|
|
|
|
- (BOOL)isRounding {
|
|
return [objc_getAssociatedObject(self, &kIsRounding) boolValue];
|
|
}
|
|
|
|
- (void)setIsRounding:(BOOL)isRounding {
|
|
objc_setAssociatedObject(self, &kIsRounding, @(isRounding), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
}
|
|
|
|
- (UIRectCorner)roundingCorners {
|
|
return [objc_getAssociatedObject(self, &kRoundingCorners) unsignedLongValue];
|
|
}
|
|
|
|
- (void)setRoundingCorners:(UIRectCorner)roundingCorners {
|
|
objc_setAssociatedObject(self, &kRoundingCorners, @(roundingCorners), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
}
|
|
|
|
- (CGFloat)radius {
|
|
return [objc_getAssociatedObject(self, &kRadius) floatValue];
|
|
}
|
|
|
|
- (void)setRadius:(CGFloat)radius {
|
|
objc_setAssociatedObject(self, &kRadius, @(radius), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
}
|
|
|
|
|
|
|
|
@end
|