主要使用这二个分类,按常用排序。cell上圆角特别需要。不然一个好像0.2m(粗算)。一个项目个人认为上限50未优化,所以cell必须优化。
1。UIImageView+CornerRadius
2。UIView+RoundedCorner
UIImage+RoundedCorner
简单使用,记录下。
UIView+RoundedCorner
#import "UIView+RoundedCorner.h" #import <objc/runtime.h> static NSOperationQueue *jm_operationQueue; static char jm_operationKey; @implementation UIView (RoundedCorner) + (void)load { jm_operationQueue = [[NSOperationQueue alloc] init]; } - (NSOperation *)jm_getOperation { id operation = objc_getAssociatedObject(self, &jm_operationKey); return operation; } - (void)jm_setOperation:(NSOperation *)operation { objc_setAssociatedObject(self, &jm_operationKey, operation, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (void)jm_cancelOperation { NSOperation *operation = [self jm_getOperation]; [operation cancel]; [self jm_setOperation:nil]; } - (void)jm_setCornerRadius:(CGFloat)radius withBorderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth { [self jm_setCornerRadius:radius withBorderColor:borderColor borderWidth:borderWidth backgroundColor:nil backgroundImage:nil contentMode:UIViewContentModeScaleAspectFill]; } - (void)jm_setJMRadius:(JMRadius)radius withBorderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth { [self jm_setJMRadius:radius withBorderColor:borderColor borderWidth:borderWidth backgroundColor:nil backgroundImage:nil contentMode:UIViewContentModeScaleAspectFill]; } - (void)jm_setCornerRadius:(CGFloat)radius withBackgroundColor:(UIColor *)backgroundColor { [self jm_setCornerRadius:radius withBorderColor:nil borderWidth:0 backgroundColor:backgroundColor backgroundImage:nil contentMode:UIViewContentModeScaleAspectFill]; } - (void)jm_setJMRadius:(JMRadius)radius withBackgroundColor:(UIColor *)backgroundColor { [self jm_setJMRadius:radius withBorderColor:nil borderWidth:0 backgroundColor:backgroundColor backgroundImage:nil contentMode:UIViewContentModeScaleAspectFill]; } - (void)jm_setCornerRadius:(CGFloat)radius withImage:(UIImage *)image { [self jm_setCornerRadius:radius withBorderColor:nil borderWidth:0 backgroundColor:nil backgroundImage:image contentMode:UIViewContentModeScaleAspectFill]; } - (void)jm_setJMRadius:(JMRadius)radius withImage:(UIImage *)image { [self jm_setJMRadius:radius withBorderColor:nil borderWidth:0 backgroundColor:nil backgroundImage:image contentMode:UIViewContentModeScaleAspectFill]; } - (void)jm_setCornerRadius:(CGFloat)radius withImage:(UIImage *)image contentMode:(UIViewContentMode)contentMode { [self jm_setCornerRadius:radius withBorderColor:nil borderWidth:0 backgroundColor:nil backgroundImage:image contentMode:contentMode]; } - (void)jm_setJMRadius:(JMRadius)radius withImage:(UIImage *)image contentMode:(UIViewContentMode)contentMode { [self jm_setJMRadius:radius withBorderColor:nil borderWidth:0 backgroundColor:nil backgroundImage:image contentMode:contentMode]; } - (void)jm_setCornerRadius:(CGFloat)radius withBorderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth backgroundColor:(UIColor *)backgroundColor backgroundImage:(UIImage *)backgroundImage contentMode:(UIViewContentMode)contentMode { [self jm_setJMRadius:JMRadiusMake(radius, radius, radius, radius) withBorderColor:borderColor borderWidth:borderWidth backgroundColor:backgroundColor backgroundImage:backgroundImage contentMode:contentMode]; } - (void)jm_setJMRadius:(JMRadius)radius withBorderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth backgroundColor:(UIColor *)backgroundColor backgroundImage:(UIImage *)backgroundImage contentMode:(UIViewContentMode)contentMode { [self jm_cancelOperation]; [self jm_setJMRadius:radius withBorderColor:borderColor borderWidth:borderWidth backgroundColor:backgroundColor backgroundImage:backgroundImage contentMode:contentMode size:CGSizeZero]; } - (void)jm_setJMRadius:(JMRadius)radius withBorderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth backgroundColor:(UIColor *)backgroundColor backgroundImage:(UIImage *)backgroundImage contentMode:(UIViewContentMode)contentMode size:(CGSize)size { __block CGSize _size = size; __weak typeof(self) wself = self; NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{ if ([[wself jm_getOperation] isCancelled]) return; if (CGSizeEqualToSize(_size, CGSizeZero)) { dispatch_sync(dispatch_get_main_queue(), ^{ _size = wself.bounds.size; }); } CGSize size2 = CGSizeMake(pixel(_size.width), pixel(_size.height)); UIImage *image = [UIImage jm_imageWithRoundedCornersAndSize:size2 JMRadius:radius borderColor:borderColor borderWidth:borderWidth backgroundColor:backgroundColor backgroundImage:backgroundImage withContentMode:contentMode]; [[NSOperationQueue mainQueue] addOperationWithBlock:^{ __strong typeof(wself) self = wself; if ([[self jm_getOperation] isCancelled]) return; self.frame = CGRectMake(pixel(self.frame.origin.x), pixel(self.frame.origin.y), size2.width, size2.height); if ([self isKindOfClass:[UIImageView class]]) { ((UIImageView *)self).image = image; } else if ([self isKindOfClass:[UIButton class]] && backgroundImage) { [((UIButton *)self) setBackgroundImage:image forState:UIControlStateNormal]; } else if ([self isKindOfClass:[UILabel class]]) { self.layer.backgroundColor = [UIColor colorWithPatternImage:image].CGColor; } else { self.layer.contents = (__bridge id _Nullable)(image.CGImage); } }]; }]; [self jm_setOperation:blockOperation]; [jm_operationQueue addOperation:blockOperation]; } static inline float pixel(float num) { float unit = 1.0 / [UIScreen mainScreen].scale; double remain = fmod(num, unit); return num - remain + (remain >= unit / 2.0? unit: 0); }
UIImage+RoundedCorner
+ (UIImage *)jm_imageWithRoundedCornersAndSize:(CGSize)sizeToFit JMRadius:(JMRadius)radius borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth backgroundColor:(UIColor *)backgroundColor backgroundImage:(UIImage *)backgroundImage withContentMode:(UIViewContentMode)contentMode { if (backgroundImage) { backgroundImage = [backgroundImage scaleToSize:CGSizeMake(sizeToFit.width, sizeToFit.height) withContentMode:contentMode backgroundColor:backgroundColor]; backgroundColor = [UIColor colorWithPatternImage:backgroundImage]; } else if (!backgroundColor){ backgroundColor = [UIColor whiteColor]; } UIGraphicsBeginImageContextWithOptions(sizeToFit, NO, UIScreen.mainScreen.scale); CGFloat halfBorderWidth = borderWidth / 2; //设置上下文 CGContextRef context = UIGraphicsGetCurrentContext(); //边框大小 CGContextSetLineWidth(context, borderWidth); //边框颜色 CGContextSetStrokeColorWithColor(context, borderColor.CGColor); //矩形填充颜色 CGContextSetFillColorWithColor(context, backgroundColor.CGColor); CGFloat height = sizeToFit.height; CGFloat width = sizeToFit.width; radius = [UIImage transformationJMRadius:radius size:sizeToFit borderWidth:borderWidth]; CGFloat startPointY; if (radius.topRightRadius >= height - borderWidth) { startPointY = height; } else if (radius.topRightRadius > 0){ startPointY = halfBorderWidth + radius.topRightRadius; } else { startPointY = 0; } CGContextMoveToPoint(context, width - halfBorderWidth, startPointY); // 开始坐标右边开始 CGContextAddArcToPoint(context, width - halfBorderWidth, height - halfBorderWidth, width / 2, height - halfBorderWidth, radius.bottomRightRadius); // 右下角角度 CGContextAddArcToPoint(context, halfBorderWidth, height - halfBorderWidth, halfBorderWidth, height / 2, radius.bottomLeftRadius); // 左下角角度 CGContextAddArcToPoint(context, halfBorderWidth, halfBorderWidth, width / 2, halfBorderWidth, radius.topLeftRadius); // 左上角 CGContextAddArcToPoint(context, width - halfBorderWidth, halfBorderWidth, width - halfBorderWidth, height / 2, radius.topRightRadius); // 右上角 CGContextDrawPath(context, kCGPathFillStroke); //根据坐标绘制路径 UIImage *outImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return outImage; }
UIImageView+CornerRadius
#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 class] swizzleMethod:NSSelectorFromString(@"dealloc") anotherMethod:@selector(zy_dealloc)]; [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 class] swizzleMethod:NSSelectorFromString(@"dealloc") anotherMethod:@selector(zy_dealloc)]; [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)zy_dealloc { if (self.hadAddObserver) { [self removeObserver:self forKeyPath:@"image"]; } [self zy_dealloc]; } - (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 { [self zy_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); }