前言
- 需求介绍:很多时候我们不希望按钮多次连按,如果去写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