// // UIButton+button.m // TTJF // // Created by wbzhan on 2018/4/24. // Copyright © 2018年 TTJF. All rights reserved. // #import "UIButton+button.h" #import @interface UIButton() @property (nonatomic, assign) BOOL isIgnoreEvent; @end @implementation UIButton (button) @dynamic hitTestEdgeInsets; static const NSString *KEY_HIT_TEST_EDGE_INSETS = @"HitTestEdgeInsets"; static const char *UIControl_timeInterval = "UIControl_timeInterval"; static const char *UIControl_enventIsIgnoreEvent = "UIControl_enventIsIgnoreEvent"; -(instancetype)init{ self = [super init]; if (self) { self.adjustsImageWhenHighlighted = NO; } return self; } -(void)setHighlighted:(BOOL)highlighted{ [super setHighlighted:NO]; } // runtime 动态绑定 属性 - (void)setIsIgnoreEvent:(BOOL)isIgnoreEvent { objc_setAssociatedObject(self, UIControl_enventIsIgnoreEvent, @(isIgnoreEvent), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (BOOL)isIgnoreEvent{ return [objc_getAssociatedObject(self, UIControl_enventIsIgnoreEvent) boolValue]; } - (NSTimeInterval)timeInterval { return [objc_getAssociatedObject(self, UIControl_timeInterval) doubleValue]; } - (void)setTimeInterval:(NSTimeInterval)timeInterval { objc_setAssociatedObject(self, UIControl_timeInterval, @(timeInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } + (void)load { // Method Swizzling static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ SEL selA = @selector(sendAction:to:forEvent:); SEL selB = @selector(after_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)after_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { self.timeInterval = self.timeInterval == 0 ? defaultInterval : self.timeInterval; if (self.isIgnoreEvent){ return; }else if (self.timeInterval > 0){ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.timeInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [self setIsIgnoreEvent:NO]; }); } self.isIgnoreEvent = YES; // 这里看上去会陷入递归调用死循环,但在运行期此方法是和sendAction:to:forEvent:互换的,相当于执行sendAction:to:forEvent:方法,所以并不会陷入死循环。 [self after_sendAction:action to:target forEvent:event]; } #pragma mark --点击区域以及button按钮文字位置 - (void)setImagePosition:(ImagePosition)postion spacing:(CGFloat)spacing { // [self setTitle:self.currentTitle forState:UIControlStateNormal]; // [self setImage:self.currentImage forState:UIControlStateNormal]; CGFloat imageWidth = self.imageView.image.size.width; CGFloat imageHeight = self.imageView.image.size.height; CGFloat labelWidth = [self.titleLabel.text sizeWithAttributes:@{NSFontAttributeName:self.titleLabel.font}].width; if (postion == ImagePositionRight && labelWidth >= self.frame.size.width - imageWidth) { labelWidth = self.frame.size.width - imageWidth; } CGFloat labelHeight = [self.titleLabel.text sizeWithAttributes:@{NSFontAttributeName:self.titleLabel.font}].height; CGFloat imageOffsetX = (imageWidth + labelWidth) / 2 - imageWidth / 2; //image中心移动的x距离 CGFloat imageOffsetY = imageHeight / 2 + spacing / 2; //image中心移动的y距离 CGFloat labelOffsetX = (imageWidth + labelWidth / 2) - (imageWidth + labelWidth) / 2; //label中心移动的x距离 CGFloat labelOffsetY = labelHeight / 2 + spacing / 2; //label中心移动的y距离 CGFloat tempWidth = MAX(labelWidth, imageWidth); CGFloat changedWidth = labelWidth + imageWidth - tempWidth; CGFloat tempHeight = MAX(labelHeight, imageHeight); CGFloat changedHeight = labelHeight + imageHeight + spacing - tempHeight; switch (postion) { case ImagePositionLeft: self.imageEdgeInsets = UIEdgeInsetsMake(0, -spacing / 2, 0, spacing / 2); self.titleEdgeInsets = UIEdgeInsetsMake(0, spacing / 2, 0, -spacing / 2); self.contentEdgeInsets = UIEdgeInsetsMake(0, spacing / 2, 0, spacing / 2); break; case ImagePositionRight: self.imageEdgeInsets = UIEdgeInsetsMake(0, labelWidth + spacing / 2, 0, -(labelWidth + spacing / 2)); self.titleEdgeInsets = UIEdgeInsetsMake(0, -(imageWidth + spacing / 2), 0, imageWidth + spacing / 2); self.contentEdgeInsets = UIEdgeInsetsMake(0, spacing / 2, 0, spacing / 2); break; case ImagePositionTop: self.imageEdgeInsets = UIEdgeInsetsMake(-imageOffsetY, imageOffsetX, imageOffsetY, -imageOffsetX); self.titleEdgeInsets = UIEdgeInsetsMake(labelOffsetY, -labelOffsetX, -labelOffsetY, labelOffsetX); self.contentEdgeInsets = UIEdgeInsetsMake(imageOffsetY, -changedWidth / 2, changedHeight - imageOffsetY, -changedWidth / 2); break; case ImagePositionBottom: self.imageEdgeInsets = UIEdgeInsetsMake(imageOffsetY, imageOffsetX, -imageOffsetY, -imageOffsetX); self.titleEdgeInsets = UIEdgeInsetsMake(-labelOffsetY, -labelOffsetX, labelOffsetY, labelOffsetX); self.contentEdgeInsets = UIEdgeInsetsMake(changedHeight - imageOffsetY, -changedWidth / 2, imageOffsetY, -changedWidth / 2); break; default: break; } } -(void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets { NSValue *value = [NSValue value:&hitTestEdgeInsets withObjCType:@encode(UIEdgeInsets)]; objc_setAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(UIEdgeInsets)hitTestEdgeInsets { NSValue *value = objc_getAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS); if(value) { UIEdgeInsets edgeInsets; [value getValue:&edgeInsets]; return edgeInsets; }else { return UIEdgeInsetsZero; } } //点击区域 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || !self.enabled || self.hidden) { return [super pointInside:point withEvent:event]; } CGRect relativeFrame = self.bounds; CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets); return CGRectContainsPoint(hitFrame, point); } @end