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的延时后 ...
随机推荐
- Vuex-Action
Action 类似于 mutation,不同在于: Action 提交的是 mutation,而不是直接变更状态. Action 可以包含任意异步操作. 让我们来注册一个简单的 action: con ...
- Python递归 — — 二分查找、斐波那契数列、三级菜单
一.二分查找 二分查找也称之为折半查找,二分查找要求线性表(存储结构)必须采用顺序存储结构,而且表中元素顺序排列. 二分查找: 1.首先,将表中间位置的元素与被查找元素比较,如果两者相等,查找结束,否 ...
- HBase 入门笔记-安装篇
一.前言 接触HBase已近半年,从一无所知到问题的解决,在数据落地方面也有了一定的了解,在此记录这半年来碰到的一些问题和对一些数据落地方面的见解,本篇主要介绍一下hbase安装方面的信息 二.安装环 ...
- print、println的区别
System.out.print("a");——后面没有换行符 System.out.println("b");——后面有换行符 换行符:\r和\n以及\r\n ...
- python开发学习-day06(模块拾忆、面向对象)
s12-20160130-day06 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...
- jquery validate表单验证插件的基本使用方法及功能拓展
1 表单验证的准备工作 在开启长篇大论之前,首先将表单验证的效果展示给大家. 1.点击表单项,显示帮助提示 2.鼠标离开表单项时,开始校验元素 3.鼠标离开后的正确.错误提示及鼠标移入时的帮助提 ...
- QT在windows平台安装使用MInGW编译
首先,Qt 5.9 的安装包与之前相比,不再区分 VS 版本和 MinGW 版本,而是全都整合到了一个安装包中.因此,与之前的安装包相比,体积也是大了不少,以前是 1G 多,现在是 2G 多. 双击启 ...
- Python并发编程-进程池回调函数
回调函数不能传参数 回调函数是在主进程中执行的 from multiprocessing import Pool import os def func1(n): print('in func1', o ...
- ActiveMQ 权限(一)
在 ActiveMQ 认证(一) 中,若用户名或密码不正确,不能连接到ActiveMQ.我们可以通过配置文件,确用户是否有消息的读取.写入和管理的权限. 在plugin配置节点下,配置以下信息: &l ...
- 苹果内存取证工具volafox
苹果内存取证工具volafox volafox是一款针对苹果内存取证的专用工具.该工具使用Python语言编写.该工具内置了overlay data数据,用户可以直接分析苹果10.6-10.11的各种 ...