UIButton禁止短时间多次点击

直接上代码了:

@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 

#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

你可能感兴趣的:(UIButton禁止短时间多次点击)