按鈕重復點擊的情況主要有兩種,一種是用戶主動點擊,這個無法避免;二是網絡耗時造成的延遲情況,促使用戶重復點擊。
-
場景一,用戶主動點擊,例如:重復的點贊和取消點贊的行為。
這種情況如果不進行處理,會造成頻繁訪問服務器的行為,造成服務器資源的浪費。
解決方法:對點擊事件進行延遲執行,再次點擊時,先取消之前的延遲事件,這樣的話,延遲時間內重復點擊的話,只會執行最后一次操作的事件。
// 當按鈕再次點擊的時候,取消之前的延遲事件,執行新的延遲事件
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(buttonClickedAction:) object:sender];
[self performSelector:@selector(buttonClickedAction:) withObject:sender afterDelay:1.0];
-
場景二,網絡延遲時造成的延遲情況下,用戶再次點擊的行為。
這種情況存在的地方很多,所以進行所有的按鈕全局處理的方案,相對比較理想。
解決方法:使用runtime的方式,自定義方法替換button的事件響應方法sendAction,在自定義方法中,設置響應延遲,即是在延遲時間內只能響應一次事件,這樣等于限制了一定的時間單位內,只能執行一次事件。
點贊等場景,不適合該方式,要單獨處理.
實現方式:給UIButton添加一個分類,然后在分類中動態添加屬性
/*
事件延遲時間
*/
@property NSTimeInterval acceptEventInterval;
/*
事件接收時間
*/
@property NSTimeInterval acceptEventTime;
/*
是否忽視事件延遲(特殊場景,不要需要延遲)
*/
@property Boolean isIgnoreEventInterval;
在.m中實現getter和setter方法,
#import <objc/message.h>
#define defaultTimeInterval 1.0 // 默認延遲1秒
static const char *AcceptEventInterval = "acceptEventInterval";
static const char *AcceptEventTime = "acceptEventTime";
static const char *IsIgnoreEventInterval = "isIgnoreEventInterval";
@implementation UIButton (Interval)
- (NSTimeInterval)acceptEventInterval{
return [objc_getAssociatedObject(self, &AcceptEventInterval) doubleValue];
}
- (void)setAcceptEventInterval:(NSTimeInterval)acceptEventInterval{
objc_setAssociatedObject(self, &AcceptEventInterval, @(acceptEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSTimeInterval)acceptEventTime{
return [objc_getAssociatedObject(self, &AcceptEventTime) doubleValue];
}
- (void)setAcceptEventTime:(NSTimeInterval)acceptEventTime{
objc_setAssociatedObject(self, &AcceptEventTime, @(acceptEventTime), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (void)setIsIgnoreEventInterval:(Boolean)isIgnoreEventInterval{
objc_setAssociatedObject(self, &IsIgnoreEventInterval, @(isIgnoreEventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (Boolean)isIgnoreEventInterval{
return [objc_getAssociatedObject(self, &IsIgnoreEventInterval) boolValue];
}
+ (void)load{
[super load];
Method fromMethod = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
Method toMethod = class_getInstanceMethod(self, @selector(xz_sendAction:to:forEvent:));
// 使用自定義的sendAction方法替換系統的sendAction方法
method_exchangeImplementations(fromMethod, toMethod);
}
- (void)xz_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{
// 如果不需要事件延遲,則不進行延遲操作
if(self.isIgnoreEventInterval == YES){
[self xz_sendAction:action to:target forEvent:event];
return;
}
// 這里處理一下,如果沒有達到事件延遲時間,則不執行
NSTimeInterval now = [NSDate date].timeIntervalSince1970;
self.acceptEventInterval = self.acceptEventInterval ? self.acceptEventInterval : defaultTimeInterval;
if (now - self.acceptEventTime < self.acceptEventInterval) {
return;
}
if (self.acceptEventInterval > 0) {
self.acceptEventTime = now;
}
// 因為方法實現已經替換,調用xz_sendAction,就是調用sendAction的實現方法,所以不會造成死循環
[self xz_sendAction:action to:target forEvent:event];
}
使用時,在需要的類中,引入這個頭文件,或者在.pch中引入;
- 通過按鈕的isIgnoreEventInterval設置是否忽略按鈕事件延遲;
btn.isIgnoreEventInterval = YES;
- 通過按鈕的acceptEventInterval設置事件延遲的時間。
btn.acceptEventInterval = 2;
最后編輯于 :
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。