美文网首页
UIButton防止按钮和手势的暴力点击

UIButton防止按钮和手势的暴力点击

作者: 龍飝 | 来源:发表于2019-08-07 10:28 被阅读0次

    首先理解下几个概念
    1、IMP:它是指向一个方法具体实现的指针,每一个方法都有一个对应的IMP,当你发起一个消息之后,最终它会执行的那段代码,就是由IMP这个函数指针指向了这个方法实现的
    2、SEL:方法名称的描述,只记录方法的编号不记录具体的方法,具体的方法是 IMP
    3、Method:是一个类实例,里面的结构体有一个方法选标 SEL – 表示该方法的名称,一个types – 表示该方法参数的类型,一个 IMP - 指向该方法的具体实现的函数指针。

    针对UIButton、UISegmentedControl、UISwitch这些继承自UIControl的控件可通过hook sendAction:to:forEvent:这个方法实现控件的重复点击
    具体思路:
    1、创建UIButton的类别,使用runtime添加public属性eventInterval作为计时因子
    2、添加private属性eventUnavailable来控制button的点击事件是否有效
    3、在+load方法中实现系统sendAction:to:forEvent:方法与自定义方法进行交换
    代码实现:

    + (void)load {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            Method origMethod = class_getInstanceMethod([self class], @selector(sendAction:to:forEvent:));
            SEL origsel = @selector(sendAction:to:forEvent:);
            Method swizMethod = class_getInstanceMethod([self class], @selector(tk_sendAction:to:forEvent:));
            SEL swizsel = @selector(tk_sendAction:to:forEvent:);
            BOOL addMehtod = class_addMethod([self class], origsel, method_getImplementation(swizMethod), method_getTypeEncoding(swizMethod));
            
            if (addMehtod) {
                class_replaceMethod([self class], swizsel, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
            } else {
                method_exchangeImplementations(origMethod, swizMethod);
            }
        });
    }
     
    - (void)tk_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
        if (self.eventUnavailable == NO) {
            self.eventUnavailable = YES;
            [self tk_sendAction:action to:target forEvent:event];
            [self performSelector:@selector(setEventUnavailable:) withObject:@(NO) afterDelay:self.eventInterval];
        }
    }
    

    针对单击事件可对UITapGestureRecognizer的initWithTarget:action:或addTarget:action:进行hook
    具体思路:
    1、创建UITapGestureRecognizer的类别,使用runtime添加public属性eventInterval作为计时因子
    2、添加private属性eventUnavailable来控制button的点击事件是否有效
    3、在+load方法中实现系统initWithTarget:action:方法与自定义方法进行交换
    4、将target和selector关联到创建的类别中并且将selector替换成类别中自定义的响应方法
    代码实现:

    - (instancetype)initTKWithTarget:(id)target action:(SEL)action {
        self = [self initTKWithTarget:self action:@selector(tap:)];
        objc_setAssociatedObject(self, gestureTargetKey, target, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        objc_setAssociatedObject(self, gestureSelKey, NSStringFromSelector(action), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        return self;
    }
     
    - (void)tap:(UIGestureRecognizer *)tapGesture {
        id target = objc_getAssociatedObject(self, gestureTargetKey);
        SEL action = NSSelectorFromString(objc_getAssociatedObject(self, gestureSelKey));
        
        if (self.eventUnavailable == NO) {
            self.eventUnavailable = YES;
            [target performSelector:action];
            [self performSelector:@selector(setEventUnavailable:) withObject:@(NO) afterDelay:self.eventInterval];
        }
    }
    

    针对单击事件的第二种实现方式实现带参数的init方法
    具体思路:
    1、在分类中实现initWithTarget:action:eventIntervl:的方法通过传进去计时因子控制点击事件是否可以响应,将手势的代理设置成新建的分类
    2、添加属性eventUnavailable来控制点击事件是否有效
    3、通过重写gestureRecognizer:shouldReceiveTouch:来控制点击事件是否响应
    代码实现:

    -(instancetype)initWithTarget:(id)target action:(SEL)action eventIntervl:(NSTimeInterval)eventIntervl {
        self = [super init];
        if (self) {
            self.eventInterval = eventIntervl;
            self.delegate = self;
            [self addTarget:target action:action];
        }
        return self;
    }
     
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
        if (self.eventUnavailable == NO) {
            self.eventUnavailable = YES;
            [self performSelector:@selector(setEventUnavailable:) withObject:@(NO) afterDelay:self.eventInterval];
            return YES;
        } else {
            return NO;
        }
    }
    

    相关文章

      网友评论

          本文标题:UIButton防止按钮和手势的暴力点击

          本文链接:https://www.haomeiwen.com/subject/yggndctx.html