iOS prevents button repeat click

Source: Internet
Author: User

The project often encounters time-consuming actions in a button's Click event. Improper handling often results in multiple clicks to push multiple times, resulting in a bad user experience.

One scenario is that the user clicks quickly and continuously, which is unavoidable. Another situation is that the response time after the Click is too long, causing the user to stay on the click Interface, and then click the button to confirm whether the next interface can be executed. Although we can use the user to display a hub window to isolate the user operation, but we do not know how long it takes the server to respond to this operation, if the hub indicator display time is too long will appear to respond particularly slow, if too short, the user is likely to click on the button after the indicator disappears, The duplicate push will also appear multiple times.

There are typically three ways to resolve this issue.

First, say one of the least recommended methods.

If your navigation is custom, you can override-(void) Pushviewcontroller: (Uiviewcontroller *) Viewcontroller animated: (BOOL) Animated method, To do this in this method, the code is as follows:

-(void) Pushviewcontroller: (Uiviewcontroller *) Viewcontroller animated: (BOOL) animated
{
if (![ [Super Topviewcontroller] Iskindofclass:[viewcontroller class]) {//If this operation is isolated from the previous controller
[Super Pushviewcontroller:viewcontroller animated:animated];
}
}

This method prevents multiple push attempts, but if the next controller you want to push is exactly the same as the previous controller type (Class), it will not push successfully. It is not recommended to use this method.

Second, click once to change the button's enabled to No.

The specific idea is that if you take a time-consuming action in a button's click event, it may be time-consuming to process the network request and request successfully. If you simply write it again in the callback of the request success and failure btn.enabled = yes you will see if the push multiple times will occur with successive clicks. The reason may be that the push operation takes time to execute, and we can make a quick click or push multiple times during this time, and it's interesting to try. My train of thought is to set Buuton's enabled to Yes separately after the request has failed, and to not do anything to the button after the request succeeds. Finally, in the-Viewwillappear method, the button's enabled is set to Yes in case the button is not clickable when the pop returns to the controller. The following code:

The Wxdhttptool is a network request class that encapsulates a layer of afnetworking.

In the-Viewwillappear method, set the enabled button to Yes:

This can also be done to prevent repetitive push problems, but not once and for all. Every controller needs to do this, although the code is not complicated, but the way is not elegant.

Three, the most elegant way, using runtime monitoring click events, ignoring the repeated click, set a Eventtimeinterval property, so that its time to respond to only one click event. Nonsense not much to say, on the code.

1, create a classification for UIButton, here I named WxD.

2. h file: Add an attribute eventtimeinterval to set the button click Interval.

#import <UIKit/UIKit.h>
@interface UIButton (WXD)
/**
* Add a click interval eventtimeinterval seconds for the button
*/
@property (nonatomic, assign) Nstimeinterval eventtimeinterval;
@end

3. m file: Requires Import<objc/runtime.h> library.

#import "Uibutton+wxd.h"
#import <objc/runtime.h>
#define DEFAULTINTERVAL 1//Default time interval

@interface UIButton ()

/**
* BOOL YES ignores click event NO allow Click event
*/
@property (nonatomic, assign) BOOL isignoreevent;

@end

@implementation UIButton (WXD)

static const char *uicontrol_eventtimeinterval = "Uicontrol_eventtimeinterval";
static const char *uicontrol_enventisignoreevent = "uicontrol_enventisignoreevent";


Runtime Dynamic Binding Properties
-(void) Setisignoreevent: (BOOL) isignoreevent
{
Objc_setassociatedobject (self, uicontrol_enventisignoreevent, @ (isignoreevent), objc_association_retain_nonatomic );
}
-(BOOL) isignoreevent{
return [Objc_getassociatedobject (self, uicontrol_enventisignoreevent) boolvalue];
}

-(Nstimeinterval) Eventtimeinterval
{
return [Objc_getassociatedobject (self, uicontrol_eventtimeinterval) Doublevalue];
}

-(void) Seteventtimeinterval: (nstimeinterval) Eventtimeinterval
{
Objc_setassociatedobject (self, uicontrol_eventtimeinterval, @ (eventtimeinterval), Objc_association_retain_ Nonatomic);
}

+ (void) load
{
Method swizzling
Static dispatch_once_t Oncetoken;
Dispatch_once (&oncetoken, ^{
SEL SelA = @selector (sendAction:to:forEvent:);
SEL Selb = @selector (_wxd_sendaction:to:forevent:);
Method MethodA = Class_getinstancemethod (Self,sela);
Method MethodB = Class_getinstancemethod (self, selb);

BOOL Isadd = Class_addmethod (self, SelA, method_getimplementation (MethodB), method_gettypeencoding (MethodB));

if (Isadd) {
Class_replacemethod (self, Selb, method_getimplementation (MethodA), method_gettypeencoding (MethodA));
}else{
Add failed the description of the implementation of METHODB in this class, at this time only need to MethodA and MethodB imp swap.
Method_exchangeimplementations (MethodA, MethodB);
}
});
}

-(void) _wxd_sendaction: (SEL) action to: (ID) Target forevent: (Uievent *) event
{
Self.eventtimeinterval = Self.eventtimeinterval = = 0? DefaultInterval:self.eventTimeInterval;
if (self.isignoreevent) {
Return
}else if (Self.eventtimeinterval > 0) {
Dispatch_after (Dispatch_time (Dispatch_time_now, (int64_t) (Self.eventtimeinterval * nsec_per_sec)), dispatch_get_ Main_queue (), ^{
[Self setisignoreevent:no];
});
}

Self.isignoreevent = YES;
This looks like a recursive call to a dead loop, but at run time this method is the same as SendAction:to:forEvent: interchange, equivalent to executing sendAction:to:forEvent: method, so it does not fall into a dead loop.
[Self _wxd_sendaction:action to:target forevent:event];
}

Finally, you can go to the controller that wants to set the click Interval to introduce the category header file, you can manually set button.eventtimeinterval = Click Interval, or you can use the default time interval without setting any value. You can also introduce a classification header file in the PCH file to have all the buttons in your project Add this classification.

Written in the end: if there is an opinion or a more elegant solution, welcome to communicate.

iOS prevents button repeat click

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.