Original articles, such as reprint address please note

Just write something for yourself that feels useful

Two methods I’ve used:

  • enabled
  • Runtime

1. Let’s talk about enabled, which is a property of UIControl, UIButton’s parent class,

default is YES. if NO, ignores touch events and subclasses may draw differently

The simple answer is whether UIButton’s click event can respond;

In practical project development, sometimes we will click a button to make a network request. In the process of network request, the button cannot be clicked again, or another network request will be made. You can use the enabled attribute to control button interaction events.

Such as the following code:


UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.enabled = NO;  
[[ApiManager shareInstance] fetchDataWithCompletionHandle:^(id data, NSError *error) {
    btn.enabled = YES;
}];

Copy the code

Most of this is done by setting the button’s Enabled property at the right time.

Special demand

Now there’s another requirement that I have, that the button doesn’t trigger the click event for a few seconds after the button is clicked, and then the Runtime comes out.

Now, there’s a second way to control sequential click events.

Let’s break a button click event to see how many methods are executed from the click to the response.

It’s in the red box


- (void)sendAction:(SEL)action to:(nullable id)target forEvent:(nullable UIEvent *)event;

- (void)sendActionsForControlEvents:(UIControlEvents)controlEvents;

Copy the code

You can see that all of the controls in UIKit are executed when the click event is triggered

sendAction:to:forEvent:

This method. So all we need to do is add some time limits to this method at runtime, and during that time limit, click do nothing.

Go directly to the code: I wrote a UIButton Category myself

UIButton+RepeatClickControl

#import <UIKit/ uikit. h> @interface UIButton (RepeatClickControl) @property (assign, nonatomic) NSTimeInterval noClickInterval; #import "UIButton+ repeatClickControl. h" #import <objc/runtime.h> static const NSTimeInterval DefautltTimeInterval = 1.0; @interface UIButton() @property (assign, nonatomic) BOOL isIngoreClick; // implementation UIButton (RepeatClickControl) + (void)load {//Method Swizzling static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ /* struct objc_method { SEL _Nonnull method_name OBJC2_UNAVAILABLE; char * _Nullable method_types OBJC2_UNAVAILABLE; IMP _Nonnull method_imp OBJC2_UNAVAILABLE; } */ / get selectDefaultButtonActionsel = @selector(sendAction:to:forEvent:); SEL changeButtonActionSEL = @selector(mySendAction:to:forEvent:); Method defaultButtonActionMethod = class_getInstanceMethod(self, defaultButtonActionSEL); Method changeButtonActionMethod = class_getInstanceMethod(self, changeButtonActionSEL); BOOL isAdd = class_addMethod(self, defaultButtonActionSEL, method_getImplementation(changeButtonActionMethod), method_getTypeEncoding(changeButtonActionMethod)); If (isAdd) {// Add successfully, Then replace the implementation method class_replaceMethod (self, changeButtonActionSEL, method_getImplementation (defaultButtonActionMethod), method_getTypeEncoding(defaultButtonActionMethod)); } else {// failed to add method, indicating that there is already a method, So direct execution method of reversal method_exchangeImplementations (defaultButtonActionMethod changeButtonActionMethod); }}); } - (void)mySendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { if ( [NSStringFromClass([self class]) IsEqualToString :@"UIButton"]) {if (self.isIngoreClick) {return; } else { self.noClickInterval = (self.noClickInterval == 0) ? defautltTimeInterval : self.noClickInterval; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(self.noClickInterval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.isIngoreClick = NO; }); } } self.isIngoreClick = YES; [self mySendAction:action to:target forEvent:event] [self mySendAction:action to:target forEvent:event] } #pragma mark - AssociatedObject - (void)setNoClickInterval:(NSTimeInterval)noClickInterval { objc_setAssociatedObject(self, @selector(noClickInterval), @(noClickInterval), OBJC_ASSOCIATION_ASSIGN); } - (NSTimeInterval)noClickInterval { return [objc_getAssociatedObject(self, @selector(noClickInterval)) doubleValue]; } - (void)setIsIngoreClick:(BOOL)isIngoreClick { objc_setAssociatedObject(self, @selector(isIngoreClick), @(isIngoreClick), OBJC_ASSOCIATION_ASSIGN); } - (BOOL)isIngoreClick { return [objc_getAssociatedObject(self, @selector(isIngoreClick)) boolValue]; } @endCopy the code

Create directly into the project interface to use, as to how many seconds you want to limit the number of seconds can be manually set, the default is 1 second can not continuously click. To set it manually, the following code can be used:

UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; BTN. NoClickInterval = 4.0; The rest of the initialization is omitted and noClickInterval can be set directly.Copy the code
I will come back again. I’m a little bit dark. See you later.