直接上代码了:
@interface UIControl (ONEActionControl)
/**
可以重复点击的时间间隔
默认为2.0
*/
@property (nonatomic,assign) NSTimeInterval timeTouchOffset;
/**
是否允许短时间多次点击
默认为NO:不允许, 设置为yes时,以上timeTouchOffset的设置将无效
*/
@property (nonatomic, assign) BOOL allowRepeatTouch;
@end
此处与网络上多数不同的地方在于:
按钮点击时,一次点击事件,runtime会调用mySendAction:to:forEvent:方法 3-4次,才会实现一次事件
如果仅允许调用第一次,那么一次完整的点击事件都不会发生。其他文章都是坑啊...
#import "UIControl+ONEActionControl.h"
#import <objc/runtime.h>
#define defaultInterval 2.0 //默认时间间隔
@interface UIControl ()
/**
是否忽略响应事件
*/
@property (nonatomic, copy) NSString *isIgnoreEvent;
/**
记录上一次点击对象
*/
@property (nonatomic, strong) UITouch *lastTouch;
@end
@implementation UIControl (ONEActionControl)
/**
应用启动时,hook住所有按钮的event
*/
+ (void)load{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selA = @selector(sendAction:to:forEvent:);
SEL selB = @selector(mySendAction: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{
method_exchangeImplementations(methodA, methodB);
}
});
}
#pragma mark - 按钮点击时,调用 (此方法同一次点击,会调用3-4次)
- (void)mySendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{
//判断 是否为UIButton及其子类, 间隔时间是否大于0, 是否允许短时间多次点击
if ([self isKindOfClass:[UIButton class]] && self.timeTouchOffset > 0 && !self.allowRepeatTouch) {
UITouch *touch = [event.allTouches allObjects].lastObject;
if (touch == self.lastTouch) {
// 同一次点击, 继续执行剩余次数
[self mySendAction:action to:target forEvent:event];
} else {
// 不是同一次touch, 需要判断是否超过了禁用时间
if (self.isIgnoreEvent) {
return;
}
// 这里用string类型是因为直接用bool的时候,通过performSelector:赋值会出错
self.isIgnoreEvent = @"1";
self.lastTouch = touch;
[self performSelector:@selector(setIsIgnoreEvent:) withObject:@"0" afterDelay:self.timeTouchOffset];
[self mySendAction:action to:target forEvent:event];
}
} else {
[self mySendAction:action to:target forEvent:event];
}
}
#pragma mark - Properties(属性)
static char kLastTouch;
- (void)setLastTouch:(UITouch *)lastTouch {
objc_setAssociatedObject(self, &kLastTouch, lastTouch, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (UITouch *)lastTouch {
return objc_getAssociatedObject(self, &kLastTouch);
}
- (NSTimeInterval)timeTouchOffset {
if (objc_getAssociatedObject(self, _cmd) == nil) {
return defaultInterval;
} else {
return [objc_getAssociatedObject(self, _cmd) doubleValue];
}
}
- (void)setTimeTouchOffset:(NSTimeInterval)timeTouchOffset {
objc_setAssociatedObject(self, @selector(timeTouchOffset), @(timeTouchOffset), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)isIgnoreEvent {
return objc_getAssociatedObject(self, _cmd);
}
- (void)setIsIgnoreEvent:(NSString *)isIgnoreEvent {
objc_setAssociatedObject(self, @selector(isIgnoreEvent), isIgnoreEvent, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)allowRepeatTouch {
return [objc_getAssociatedObject(self, _cmd) boolValue];
}
- (void)setAllowRepeatTouch:(BOOL)allowRepeatTouch {
objc_setAssociatedObject(self, @selector(allowRepeatTouch), @(allowRepeatTouch), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
网友评论