級別:★★☆☆☆
標籤:「UIButton Runtime」「UIButton點選頻率」「UIButton防止多次點選」
作者: Xs·H
有幾個實際業務場景需要控制UIButton響應事件的時間間隔。比如:
1、當通過點選按鈕來執行網路請求時,若請求耗時稍長,使用者往往會再點一次。這樣,就執行了兩次請求,造成了資源浪費。
2、在移動終端效能較差時(比如iPhone 6升級到iOS 11?),連續點選按鈕會執行多次事件(比如push出來多個viewController)。
3、防止暴力點選。
控制按鈕響應事件時間間隔的方案不止一種。比如:
- 方案 1:通過UIButton的enabled屬性和userInteractionEnabled屬性控制按鈕是否可點選。此方案在邏輯上比較清晰、易懂,但具體程式碼書寫分散,常常涉及多個方法。
- (void)buttonClicked:(UIButton *)sender {
sender.enabled = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
sender.enabled = YES;
});
}
複製程式碼
- 方案2:通過NSObject的+cancelPreviousPerformRequestsWithTarget:selector:object:方法和-performSelector:withObject:afterDelay:方法控制按鈕的響應事件的執行時間間隔。此方案會在連續點選按鈕時取消之前的點選事件,從而只執行最後一次點選事件,會出現延遲現象。
- (void)buttonClicked:(UIButton *)sender {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(buttonClickedAction:) object:sender];
[self performSelector:@selector(buttonClickedAction:) withObject:sender afterDelay:2.0];
}
複製程式碼
在需要對大量UIButton做控制的場景中,方案1和方案2會比較不方便。針對此場景,著重說一下方案3。
- 方案3:通過Runtime控制UIButton響應事件的時間間隔。思路如下:
1、建立一個UIButton的類別,使用runtime為UIButton增加public屬性qi_eventInterval和private屬性eventUnavailable。
2、在+load方法中使用runtime將UIButton的-sendAction:to:forEvent:方法與自定義的-qi_sendAction:to:forEvent:方法交換Implementation。
3、使用qi_eventInterval作為控制eventUnavailable的計時因子,用eventUnavailable開控制UIButton的event事件是否有效。
方案3可以對所有UIButton生效,具體實現程式碼如下:
@interface UIButton (QiEventInterval)
@property (nonatomic, assign) NSTimeInterval qi_eventInterval;
@end
複製程式碼
#import "UIButton+QiEventInterval.h"
#import <objc/runtime.h>
static char * const qi_eventIntervalKey = "qi_eventIntervalKey";
static char * const eventUnavailableKey = "eventUnavailableKey";
@interface UIButton ()
@property (nonatomic, assign) BOOL eventUnavailable;
@end
@implementation UIButton (QiEventInterval)
+ (void)load {
Method method = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:));
Method qi_method = class_getInstanceMethod(self, @selector(qi_sendAction:to:forEvent:));
method_exchangeImplementations(method, qi_method);
}
#pragma mark - Action functions
- (void)qi_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
if (self.eventUnavailable == NO) {
self.eventUnavailable = YES;
[self qi_sendAction:action to:target forEvent:event];
[self performSelector:@selector(setEventUnavailable:) withObject:@(NO) afterDelay:self.qi_eventInterval];
}
}
#pragma mark - Setter & Getter functions
- (NSTimeInterval)qi_eventInterval {
return [objc_getAssociatedObject(self, qi_eventIntervalKey) doubleValue];
}
- (void)setQi_eventInterval:(NSTimeInterval)qi_eventInterval {
objc_setAssociatedObject(self, qi_eventIntervalKey, @(qi_eventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)eventUnavailable {
return [objc_getAssociatedObject(self, eventUnavailableKey) boolValue];
}
- (void)setEventUnavailable:(BOOL)eventUnavailable {
objc_setAssociatedObject(self, eventUnavailableKey, @(eventUnavailable), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
複製程式碼
使用方法:
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
/* here is some button's configuration codes */
[self.view addSubview:button];
//! 設定按鈕的點選響應間隔時間
button.qi_eventInterval = 2.0;
複製程式碼
效果展示:
- 預設Button點選效果:
- 設定qi_eventInterval為2秒:
可從Github獲取工程原始碼
關注我們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公眾號)