iOS Button連按處理防止按鈕連續點擊

前言

  • 需求介紹:不少時候咱們不但願按鈕屢次連按,若是去寫Enabled略顯麻煩,這裏提供一種控制按鈕點擊間隔時間的方法,我已封裝方便使用

GitHub地址:KJEmitterViewgit

API

/* ******************這兩個屬性互斥********************/
/// 接受點擊事件的時間間隔
@property (nonatomic, assign) NSTimeInterval kj_AcceptEventTime;
/// 接受點擊事件執行處理以後的時間間隔
@property (nonatomic, assign) NSTimeInterval kj_AcceptDealTime;
/* ******************這兩個屬性互斥********************/
複製代碼

Runtime方法交換

內部以Category的方式實現,考慮到侵入性問題,因此沒有將方法交換放在load裏面,而是選擇以委託(KJButtonTimeExchangeMethodProtocol)的形式,內部採用 dispatch_once 的方式保證只調用一次github

@protocol KJButtonTimeExchangeMethodProtocol <NSObject>
@required
/// 是否開啓時間間隔的方法交換
+ (void)kj_openTimeExchangeMethod;
@end
複製代碼

能夠選擇在任何你要使用屬性kj_AcceptEventTimekj_AcceptDealTime 以前調用便可,例如viewDidLoadmarkdown

[UIButton kj_openTimeExchangeMethod];
複製代碼

其實就是交換方法 sendAction:to:forEvent:,在 kj_sendAction:to:forEvent: 當中判斷時間間隔ide

/// 交換方法後實現
- (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_AcceptEventTimekj_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
複製代碼

粗略封裝,望大神幫助修改完善

備註:本文用到的部分函數方法和Demo,均來自三方庫**KJEmitterView**,若有須要的朋友可自行pod 'KJEmitterView'引入便可

Button處理介紹就到此完畢,後面有相關再補充,寫文章不容易,還請點個**小星星**傳送門

相關文章
相關標籤/搜索