iOS防止button重复点击
项目中常会遇到在按钮的点击事件中去执行一些耗时操作。如果处理不当经常会出现连续多次点击push多次的情况,造成不好的用户体验。
一种情况是用户快速连续点击,这种情况无法避免。另一种情况是点击一次后响应时间太长,导致用户一直停留在点击界面,也会去再此点击按钮确认是否能执行下一个界面。虽然我们可以在用户点击一次后去显示一个HUB窗口隔绝用户操作,但我们并不清楚服务器去响应这个操作究竟需要多长时间,如果HUB指示器显示时间太长会显得响应特别慢,如果太短,用户很可能在指示器消失后再去点击Button,这时也会出现重复push多次。
通常有三种方式解决此问题。
一、先说一种最不推荐使用的方法。
如果你的Navigation是自定义的,可以重写- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated方法,在此方法中做处理,代码如下:
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (![[super topViewController] isKindOfClass:[viewController class]]) { // 如果和上一个控制器一样,隔绝此操作
[super pushViewController:viewController animated:animated];
}
}
此中方法可以防止多次重复push,但如果你想push的下一个控制器恰好和上一个控制器类型(Class)一样,就不会push成功。所以并不推荐使用此方法。
二、第二种方式,点击一次后将button的enabled变为NO。
具体思路是:如果在button的点击事件中要做耗时操作,可能是网络请求和请求成功后的数据处理比较耗时。如果只是单纯的在请求成功和失败的回调中写一遍btn.enabled = YES就会发现如果连续点击还是会出现push多次的情况。原因可能是push操作需要时间去执行,我们在这段时间连续快速点击还是会导致push多次,感兴趣的可以去试一下。我的思路是在请求失败后单独将buuton的enabled设为YES,请求成功后不对button做任何操作。最后在- viewWillAppear方法中将button的enabled设为YES,以防在pop回本控制器的时候button不可点击。下面上代码:

其中的WXDHTTPTool是封装了一层AFNetworking的网络请求类。
在- viewWillAppear方法中将button的enabled设为YES:

这样做也可以实现防止重复push的问题,但并不能做到一劳永逸。每个控制器都需要这么去做,虽然代码并不复杂,但方式并不优雅。
三、最优雅的方式,使用Runtime监听点击事件,忽略重复点击,设置一个eventTimeInterval属性,使其规定时间内只响应一次点击事件。废话不多说,上代码。
1、为UIButton创建一个分类,这里我起名为WXD。
2、.h文件:添加一个属性eventTimeInterval,用来设置button点击间隔时间。
#import <UIKit/UIKit.h>
@interface UIButton (WXD)
/**
* 为按钮添加点击间隔 eventTimeInterval秒
*/
@property (nonatomic, assign) NSTimeInterval eventTimeInterval;
@end
3、.m文件:需要import<objc/runtime.h>库。
#import "UIButton+WXD.h"
#import <objc/runtime.h>
#define defaultInterval 1 //默认时间间隔
@interface UIButton ()
/**
* bool YES 忽略点击事件 NO 允许点击事件
*/
@property (nonatomic, assign) BOOL isIgnoreEvent;
@end
@implementation UIButton (WXD)
static const char *UIControl_eventTimeInterval = "UIControl_eventTimeInterval";
static const char *UIControl_enventIsIgnoreEvent = "UIControl_enventIsIgnoreEvent";
// runtime 动态绑定 属性
- (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{
//添加失败了 说明本类中有methodB的实现,此时只需要将methodA和methodB的IMP互换一下即可。
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;
// 这里看上去会陷入递归调用死循环,但在运行期此方法是和sendAction:to:forEvent:互换的,相当于执行sendAction:to:forEvent:方法,所以并不会陷入死循环。
[self _wxd_sendAction:action to:target forEvent:event];
}
最后就可以去在想要设置点击间隔的控制器引入分类的头文件,可以手动设置button.eventTimeInterval = 点击间隔,也可以不设任何值去使用默认的时间间隔。还可以在pch文件中引入分类头文件,让项目中所有button都添加此分类。
写在最后:如果有意见或者更优雅的解决方式,欢迎沟通交流。
iOS防止button重复点击的更多相关文章
- iOS修改button的点击范围
一般来说,按钮的点击范围是跟按钮的大小一样的.若按钮很小时,想增大点击区域,网上通用的方法有①设置btn图片setImage,然后将btn的size设置的比图片大②在btn上添加一个比较大的透明btn ...
- 回车键和button按钮都绑定同一个事件,如何避免按回车的时候button重复点击
保存一个全局变量,用来记录Button的焦点状态 <button onclick="login();" onfocus="window.buttonIsFocuse ...
- iOS 防止UIButton重复点击
使用UIButton的enabled或userInteractionEnabled 使用UIButton的enabled属性, 在点击后, 禁止UIButton的交互, 直到完成指定任务之后再将其en ...
- iOS之防止用户重复点击Button(按钮)问题
在项目中,我们往往会遇到这样的问题:因为网络较慢的原因,用户会不耐烦的一直去点击按钮,这样导致的结果时:相关代码一遍一遍的被重复执行,如果按钮的事件是网络请求的话,这样又导致一种网络请求的循环.所以我 ...
- 限制 button 在 3 秒内不可重复点击
在下载或者上传文件过程中避免重复点击带来的多次同样的请求造成资源浪费,限制 button 的点击次数是很有必要的. 1. 增强用户体验,2. 减轻服务器压力. HTML 代码 <button i ...
- iOS小技巧:用runtime 解决UIButton 重复点击问题
http://www.cocoachina.com/ios/20150911/13260.html 作者:uxyheaven 授权本站转载. 什么是这个问题 我们的按钮是点击一次响应一次, 即使频繁的 ...
- iOS不得姐项目--TabBar的重复点击实现当前模块刷新;状态栏点击实现当前模块回滚到最顶部
一.实现功能:重复点击tabBar,刷新当前TableView,其余不受影响 <1>实现思路: 错误的方法: TabBar成为自己的代理,监听自己的点击--这种方法是不可取的,如果外面设置 ...
- ios 添加到cell 上的button点击无效!扩大button的点击区域(黑魔法)
一般情况下点击效果都是正常的!要不然你对它做了什么?一般细心的小伙伴都没有遇到这种情况,但是呢! 当然我是二班的!在这里我主要讲两个问题,解决问题和普及魔法. 一.普及问题(button在cell上点 ...
- iOS小技巧–用runtime 解决UIButton 重复点击问题
什么是这个问题 我们的按钮是点击一次响应一次, 即使频繁的点击也不会出问题, 可是某些场景下还偏偏就是会出问题. 通常是如何解决 我们通常会在按钮点击的时候设置这个按钮不可点击. 等待0.xS的延时后 ...
随机推荐
- git服务器的简单搭建
安装git 安装git,参考:https://git-scm.com/book/zh/v1/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git 创建git仓库 使用ro ...
- ubuntu10.04 svn安装方法
ubuntu10.04 svn安装方法:sudo apt-get install subversion sudo apt-get install libneon27-dev orsudo apt-ge ...
- linux系统查找具体进程
ps -ef | grep '查找内容' eg:ps -ef | grep '测试USB设备穿透'
- MySQL三种备份
一)备份分类 1 2 3 4 5 6 7 8 9 10 11 12 冷备:cold backup数据必须下线后备份 温备:warm backup全局施加共享锁,只能读,不能写 热备:hot backu ...
- ansible报错Aborting, target uses selinux but python bindings (libselinux-python) aren't installed
报错内容: TASK [activemq : jvm configuration] ********************************************************** ...
- mac 安装mongodb与常用操作
1.安装 brew update brew install mongodb 2.启动mongo mongod --config /usr/local/etc/mongod.conf 3.启动 mong ...
- 认识hasLayout——IE浏览器css bug的一大罪恶根源 (转)
认识hasLayout--IE浏览器css bug的一大罪恶根源 转 什么是hasLayout?hasLayout是IE特有的一个属性.很多的ie下的css bug都与其息息相关.在ie中,一个元素要 ...
- iOS控制器与视图加载方法
转载记录, 请看原文: 1. iOS中的各种加载方法(initWithNibName,loadNibNamed,initWithCoder,awakeFromNib等等)简单使用 http://w ...
- vim 图册
网上看到的一些图,感觉不错,分享一下 我现在感觉配置文件,很多没有必要,反而很花哨,但是这些基础的东西,反而很高效,实在 VIM的列编辑操作 删除列 1.光标定位到要操作的地方. 2.CTRL+v 进 ...
- 在WebClient类中保持Session
string url = context.Request["url"]; WebClient MyWebClient = new WebClient(); // 获取或设置用于向I ...