// // UIButton+EnlargeTouchArea.m // XCCategrayKit // // Created by Macx on 2018/8/30. // Copyright © 2018年 KevinWang. All rights reserved. // #import "UIButton+EnlargeTouchArea.h" #import #define defaultInterval 0.0003 //默认时间间隔,不能太长,以免影响系统拍照等功能 @interface UIButton () /** * bool YES 忽略点击事件 NO 允许点击事件 */ @property (nonatomic, assign) BOOL isIgnoreEvent; @end @implementation UIButton (EnlargeTouchArea) static const char *UIControl_acceptEventInterval = "UIControl_acceptEventInterval"; static const char *UIControl_enventIsIgnoreEvent = "UIControl_enventIsIgnoreEvent"; //定义常量 必须是C语言字符串 static const char *imageFrameStr = "imageFrame"; static const char *titleFrameStr = "titleFrame"; + (void)load{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Method newImageMethod = class_getInstanceMethod(self, @selector(new_imageRectForContentRect:)); Method oldImageMethod = class_getInstanceMethod(self, @selector(imageRectForContentRect:)); method_exchangeImplementations(newImageMethod, oldImageMethod); Method newTitleMethod = class_getInstanceMethod(self, @selector(new_titleRectForContentRect:)); Method oldTitleMethod = class_getInstanceMethod(self, @selector(titleRectForContentRect:)); method_exchangeImplementations(newTitleMethod, oldTitleMethod); //根据selector查找Method SEL selA = @selector(sendAction:to:forEvent:); SEL selB = @selector(new_sendAction:to:forEvent:); Method methodA = class_getInstanceMethod(self,selA); Method methodB = class_getInstanceMethod(self, selB); //添加自定义方法 BOOL isAdd = class_addMethod(self, selA, method_getImplementation(methodB), method_getTypeEncoding(methodB)); if (isAdd) {//添加成功->替换 class_replaceMethod(self, selB, method_getImplementation(methodA), method_getTypeEncoding(methodA)); }else{//添加不成功->交换 //添加失败了 说明本类中有methodB的实现,此时只需要将methodA和methodB的IMP互换一下即可。 method_exchangeImplementations(methodA, methodB); } }); } - (void)new_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { self.yn_acceptEventInterval = self.yn_acceptEventInterval == 0 ? defaultInterval : self.yn_acceptEventInterval; if (self.isIgnoreEvent){//默认可以响应点击事件 return; } if (self.yn_acceptEventInterval > 0){//第一次点击,设定eventTimeInterval后,可以响应点击事件 [self performSelector:@selector(setNoIgnoreEvent) withObject:nil afterDelay:self.yn_acceptEventInterval]; } self.isIgnoreEvent = YES;//设置不可以响应点击事件 [self new_sendAction:action to:target forEvent:event]; } // runtime 动态绑定 属性 - (BOOL)isIgnoreEvent{ return [objc_getAssociatedObject(self, UIControl_enventIsIgnoreEvent) boolValue]; } -(void)setNoIgnoreEvent{ self.isIgnoreEvent = NO; } - (void)setIsIgnoreEvent:(BOOL)isIgnoreEvent { objc_setAssociatedObject(self, UIControl_enventIsIgnoreEvent, @(isIgnoreEvent), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(void)setYn_acceptEventInterval:(NSTimeInterval)yn_acceptEventInterval{ objc_setAssociatedObject(self, UIControl_acceptEventInterval, @(yn_acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(NSTimeInterval)yn_acceptEventInterval{ return [objc_getAssociatedObject(self, UIControl_acceptEventInterval) doubleValue]; } - (void)setImageFrame:(NSValue *)imageFrame{ objc_setAssociatedObject(self, imageFrameStr, imageFrame, OBJC_ASSOCIATION_RETAIN); } - (NSValue *)imageFrame{ return objc_getAssociatedObject(self, imageFrameStr); } - (void)setTitleFrame:(NSValue *)titleFrame{ objc_setAssociatedObject(self, titleFrameStr, titleFrame, OBJC_ASSOCIATION_RETAIN); } - (NSValue *)titleFrame{ return objc_getAssociatedObject(self, titleFrameStr); } - (CGRect)new_imageRectForContentRect:(CGRect)contentRect{ if (CGRectEqualToRect(self.imageFrame.CGRectValue, CGRectZero)) { return [self new_imageRectForContentRect:contentRect]; } return self.imageFrame.CGRectValue; } - (CGRect)new_titleRectForContentRect:(CGRect)contentRect{ if (CGRectEqualToRect(self.titleFrame.CGRectValue, CGRectZero)) { return [self new_titleRectForContentRect:contentRect]; } return self.titleFrame.CGRectValue; } static char topNameKey; static char rightNameKey; static char bottomNameKey; static char leftNameKey; - (void)setEnlargeEdgeWithTop:(CGFloat)top right:(CGFloat)right bottom:(CGFloat)bottom left:(CGFloat)left { objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC); objc_setAssociatedObject(self, &rightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC); objc_setAssociatedObject(self, &bottomNameKey, [NSNumber numberWithFloat:bottom], OBJC_ASSOCIATION_COPY_NONATOMIC); objc_setAssociatedObject(self, &leftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC); } - (void)enlargeTouchArea:(UIEdgeInsets)insets { [self setEnlargeEdgeWithTop:insets.top right:insets.right bottom:insets.bottom left:insets.left]; } - (CGRect)enlargedRect { NSNumber* topEdge = objc_getAssociatedObject(self, &topNameKey); NSNumber* rightEdge = objc_getAssociatedObject(self, &rightNameKey); NSNumber* bottomEdge = objc_getAssociatedObject(self, &bottomNameKey); NSNumber* leftEdge = objc_getAssociatedObject(self, &leftNameKey); if (topEdge && rightEdge && bottomEdge && leftEdge) { return CGRectMake(self.bounds.origin.x - leftEdge.floatValue, self.bounds.origin.y - topEdge.floatValue, self.bounds.size.width + leftEdge.floatValue + rightEdge.floatValue, self.bounds.size.height + topEdge.floatValue + bottomEdge.floatValue); } else { return self.bounds; } } - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { if(self.hidden) return nil; CGRect rect = [self enlargedRect]; if (CGRectEqualToRect(rect, self.bounds)) { return [super hitTest:point withEvent:event]; } return CGRectContainsPoint(rect, point) ? self : nil; } +(UIButton *)buttonInitWithText:(NSString *)text font:(UIFont *)font textColor:(UIColor *)textColor image:(UIImage *)image bgImage:(UIImage *)bgImage{ UIButton *button = [[UIButton alloc]initWithFrame:CGRectZero]; if(text.length > 0){ [button setTitle:text forState:UIControlStateNormal]; } if(font != nil){ button.titleLabel.font = font; } if(textColor != nil){ [button setTitleColor:textColor forState:UIControlStateNormal]; } if (image != nil){ [button setImage:image forState:UIControlStateNormal]; } if(bgImage != nil){ [button setBackgroundImage:bgImage forState:UIControlStateNormal]; } return button; } @end