前言
需求介绍:很多时候我们不希望按钮多次连按,如果去写Enabled略显麻烦,这里提供一种控制按钮点击间隔时间的方法,我已封装方便使用
GitHub地址:KJCategories
API
/* ******************这两个属性互斥********************/ /// 接受点击事件的时间间隔 @property (nonatomic, assign) NSTimeInterval kj_AcceptEventTime; /// 接受点击事件执行处理之后的时间间隔 @property (nonatomic, assign) NSTimeInterval kj_AcceptDealTime; /* ******************这两个属性互斥********************/
Runtime方法交换
内部以Category的方式实现,考虑到侵入性问题,所以没有将方法交换放在load
里面,而是选择以委托(KJButtonTimeExchangeMethodProtocol
)的形式,内部采用 dispatch_once
的方式保证只调用一次
@protocol KJButtonTimeExchangeMethodProtocol <NSObject> @required /// 是否开启时间间隔的方法交换 + (void)kj_openTimeExchangeMethod; @end
可以选择在任何你要使用属性kj_AcceptEventTime
或 kj_AcceptDealTime
之前调用即可,例如viewDidLoad
[UIButton kj_openTimeExchangeMethod];
其实就是交换方法 sendAction:to:forEvent:
,在 kj_sendAction:to:forEvent:
当中判断时间间隔
/// 交换方法后实现 - (void)kj_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{ if (self.kj_AcceptEventTime <= 0 && self.kj_AcceptDealTime <= 0) { [self kj_sendAction:action to:target forEvent:event]; return; } NSTimeInterval time = self.kj_AcceptEventTime > 0 ? self.kj_AcceptEventTime : self.kj_AcceptDealTime; BOOL boo = (CFAbsoluteTimeGetCurrent() - self.kLastTime >= time); if (self.kj_AcceptEventTime > 0) { self.kLastTime = CFAbsoluteTimeGetCurrent(); } if (boo) { if (self.kj_AcceptDealTime > 0) { self.kLastTime = CFAbsoluteTimeGetCurrent(); } [self kj_sendAction:action to:target forEvent:event]; } }
如不需要点击事件间隔处理了,只需要将 kj_AcceptEventTime
和kj_AcceptDealTime
两个属性值设置为非正数即可
实现
// // UIButton+KJBlock.m // KJEmitterView // // Created by 杨科军 on 2019/4/4. // Copyright © 2019 杨科军. All rights reserved. // https://github.com/yangKJ/KJExtensionHandler #import "UIButton+KJBlock.h" #import <objc/runtime.h> @implementation UIButton (KJBlock) static char kParameterTag; /// 添加点击事件,默认UIControlEventTouchUpInside - (void)kj_addAction:(KJButtonBlock)block{ objc_setAssociatedObject(self, &kParameterTag, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC); [self addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside]; } /// 添加事件 - (void)kj_addAction:(KJButtonBlock)block forControlEvents:(UIControlEvents)controlEvents{ objc_setAssociatedObject(self, &kParameterTag, block, OBJC_ASSOCIATION_RETAIN_NONATOMIC); [self addTarget:self action:@selector(action:) forControlEvents:controlEvents]; } /// 事件响应方法 - (void)action:(UIButton*)sender{ KJButtonBlock block = objc_getAssociatedObject(self, &kParameterTag); if (block) block(self); } #pragma mark - 时间相关方法交换 /// 是否开启时间间隔的方法交换 + (void)kj_openTimeExchangeMethod{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ SEL originalSelector = @selector(sendAction:to:forEvent:); SEL swizzledSelector = @selector(kj_sendAction:to:forEvent:); Class clazz = [self class]; Method originalMethod = class_getInstanceMethod(clazz, originalSelector); Method swizzledMethod = class_getInstanceMethod(clazz, swizzledSelector); BOOL boo = class_addMethod(clazz, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if (boo) { class_replaceMethod(clazz, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); }else { method_exchangeImplementations(originalMethod, swizzledMethod); } }); } /// 交换方法后实现 - (void)kj_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{ if (self.kj_AcceptEventTime <= 0 && self.kj_AcceptDealTime <= 0) { [self kj_sendAction:action to:target forEvent:event]; return; } NSTimeInterval time = self.kj_AcceptEventTime > 0 ? self.kj_AcceptEventTime : self.kj_AcceptDealTime; BOOL boo = (CFAbsoluteTimeGetCurrent() - self.kLastTime >= time); if (self.kj_AcceptEventTime > 0) { self.kLastTime = CFAbsoluteTimeGetCurrent(); } if (boo) { if (self.kj_AcceptDealTime > 0) { self.kLastTime = CFAbsoluteTimeGetCurrent(); } [self kj_sendAction:action to:target forEvent:event]; } } - (NSTimeInterval)kj_AcceptEventTime{ return [objc_getAssociatedObject(self, @selector(kj_AcceptEventTime)) doubleValue]; } - (void)setKj_AcceptEventTime:(NSTimeInterval)kj_AcceptEventTime{ objc_setAssociatedObject(self, @selector(kj_AcceptEventTime), @(kj_AcceptEventTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSTimeInterval)kj_AcceptDealTime{ return [objc_getAssociatedObject(self, @selector(kj_AcceptDealTime)) doubleValue]; } - (void)setKj_AcceptDealTime:(NSTimeInterval)kj_AcceptDealTime{ objc_setAssociatedObject(self, @selector(kj_AcceptDealTime), @(kj_AcceptDealTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSTimeInterval)kLastTime{ return [objc_getAssociatedObject(self, @selector(kLastTime)) doubleValue]; } - (void)setKLastTime:(NSTimeInterval)kLastTime{ objc_setAssociatedObject(self, @selector(kLastTime), @(kLastTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC); } @end