iOS 按钮、Cell暴力点击触发多次响应的问题研究
2017-07-31 15:18
423 查看
在app使用的过程中,由于网络差,手机卡顿等问题,用户在不经意的时候可能多次操作,造成多次请求、或者页面多次push等,给用户带来了不好的体验,那么如何解决相关的问题呢?本文介绍几种解决办法,在某种程度上可以减少这类事件的发生,但是都未能优雅完美的解决根本问题,如果读者有更好的解决办法,欢迎留言讨论。
一、按钮的暴力点击
方案一:通过设置enable属性
点评:这种方案通过点击按钮时,将按钮的响应点击能力关闭,当完成某中业务(如数据获取)时再开启。
优点:满足我们最终想要的需求
缺点:每个按钮都需要这样手动设置,开启时需要格外的注意适当的时机,否则适得其反
方案二:设置响应点击事件的时间间隔(不推荐)
点评:这种方案是每次点击时,取消上次的响应事件,并设置为延迟执行,如果用户在延迟执行的时间间隔内一直点击,则点击事件一直被取消,不会执行,虽然可以避免用户的暴力操作,但是第一次点击都不会被执行,不能及时响应,用户体验极差,不推荐,除非业务需要就是如此
优点:无
方案三:分类
该例子实现了UIButton的父类UIControl,通过运行时来实现按钮的间断响应功能
.h 文件
.m 文件
使用:
点评:上述两种的结合,使用分类并设置点击响应时间间隔
优点:可以在不改变原有UIButton点击事件的基础上减少暴力点击的发生,一劳永逸;相比方案二,可以及时响应点击事件,并在时间间隔后继续响应
缺点:需要新建分类文件,代码多;通过设置响应时间间隔并不能完美解决暴力点击的问题,因为有时候网络请求慢,用户可能会在时间间隔外再次点击按钮(这时候则需要我们取消上次网络请求)
方案四:分类的另外一种设想
我的另外一种想法是,在点击事件发生时,即改变按钮的enable属性为NO,锁定按钮不可点击,在某个阶段时再将enable设为YES
则分类文件中,自定义响应事件变为:
再执行完点击业务时再将enable设置为YES;
点评:这种方案结合了方案一和方案三,但是个人认为这样做还不如方案一来的简洁直观
优点:只需在合适的时机开启enable;可以手动设置enable,掌握可响应时机
缺点:不直观
总结:个人还是推荐方案一和方案三,当然方案一想必是我们一直使用的手段,方案三提供了一种新的解决思路。如果方案四UIControl的分类可以自身获取到开启enable的时机,不失为暴力点击最完美的解决方案了,可以笔者能力有限,如果有读者有更好的解决方案,欢迎赐教。
二、cell的暴力点击
本着模仿UIButton的思路来解决cell的暴力点击,但是UITableView和UIBttoun的种种的不同,都未能找到较好的方案,只能粗暴一点的处理了。。。
暴力方案:使用标志符
点评:这种方法适用大部分的响应事件,包括按钮点击事件,tableView的点击事件,或者手势等,只是这样处理显得太粗暴,一点都不优雅,但是笔者现在能力有限,实在想不到其他比较好的方式了,555,如果读者有更好的解决方案,不吝赐教啊,感谢!
三、相关阅读
1、iOS 分类和扩展
2、iOS 运行时(runtime)
3、iOS UIButton点击事件传递参数的解决办法
一、按钮的暴力点击
方案一:通过设置enable属性
-(void)btnAction:(UIButton*)btn{ btn.enabled = NO; // do something btn.enabled = YES; }
点评:这种方案通过点击按钮时,将按钮的响应点击能力关闭,当完成某中业务(如数据获取)时再开启。
优点:满足我们最终想要的需求
缺点:每个按钮都需要这样手动设置,开启时需要格外的注意适当的时机,否则适得其反
方案二:设置响应点击事件的时间间隔(不推荐)
-(void)btnAction:(UIButton*)btn{ [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(doSomeThing) object:btn]; [self performSelector:@selector(doSomeThing) withObject:btn afterDelay:2.0f];// 时间间隔 } -(void)doSomeThing{ NSLog(@"click"); }
点评:这种方案是每次点击时,取消上次的响应事件,并设置为延迟执行,如果用户在延迟执行的时间间隔内一直点击,则点击事件一直被取消,不会执行,虽然可以避免用户的暴力操作,但是第一次点击都不会被执行,不能及时响应,用户体验极差,不推荐,除非业务需要就是如此
优点:无
方案三:分类
该例子实现了UIButton的父类UIControl,通过运行时来实现按钮的间断响应功能
.h 文件
@interface UIControl (NonViolentClicked) // 接受事件响应的时间间隔,开放出来供外部设置 @property (nonatomic, assign) NSTimeInterval acceptEventInterval; @end
.m 文件
#import <objc/runtime.h> // 运行时 @interface UIControl () @property (nonatomic, assign) BOOL ignoreEvent; // 是否忽视点击的事件 @end @implementation UIControl (NonViolentClicked) // 使用运行时关联UIControl的点击事件 +(void)load { Method a = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:)); Method b = class_getInstanceMethod(self, @selector(custom_sendAction:to:forEvent:)); method_exchangeImplementations(a, b); } // 自定义的点击事件 - (void)custom_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { if (self.ignoreEvent) return; if (self.acceptEventInterval > 0){ self.ignoreEvent = YES; [self performSelector:@selector(setIgnoreEvent:) withObject:@(NO) afterDelay:self.acceptEventInterval]; } [self custom_sendAction:action to:target forEvent:event]; } // 实现acceptEventInterval的getter方法 -(NSTimeInterval)acceptEventInterval{ return [objc_getAssociatedObject(self, _cmd) doubleValue]?[objc_getAssociatedObject(self, _cmd) doubleValue]:1.0; // 默认的响应时间为1秒 } // 实现acceptEventInterval的setter方法 -(void)setAcceptEventInterval:(NSTimeInterval)acceptEventInterval{ objc_setAssociatedObject(self, @selector(acceptEventInterval), [NSNumber numberWithDouble:acceptEventInterval], OBJC_ASSOCIATION_ASSIGN); } // 实现ignoreEvent的getter方法 -(BOOL)ignoreEvent{ return [objc_getAssociatedObject(self, _cmd) doubleValue]; } // 实现ignoreEvent的setter方法 -(void)setIgnoreEvent:(BOOL)ignoreEvent{ objc_setAssociatedObject(self, @selector(ignoreEvent), [NSNumber numberWithBool:ignoreEvent], OBJC_ASSOCIATION_ASSIGN); }
使用:
-(void)btnAction:(UIButton*)btn{ NSLog(@"click"); }
点评:上述两种的结合,使用分类并设置点击响应时间间隔
优点:可以在不改变原有UIButton点击事件的基础上减少暴力点击的发生,一劳永逸;相比方案二,可以及时响应点击事件,并在时间间隔后继续响应
缺点:需要新建分类文件,代码多;通过设置响应时间间隔并不能完美解决暴力点击的问题,因为有时候网络请求慢,用户可能会在时间间隔外再次点击按钮(这时候则需要我们取消上次网络请求)
方案四:分类的另外一种设想
我的另外一种想法是,在点击事件发生时,即改变按钮的enable属性为NO,锁定按钮不可点击,在某个阶段时再将enable设为YES
则分类文件中,自定义响应事件变为:
- (void)custom_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { self.enabled = NO; // 不响应点击事件 [self custom_sendAction:action to:target forEvent:event]; }
再执行完点击业务时再将enable设置为YES;
点评:这种方案结合了方案一和方案三,但是个人认为这样做还不如方案一来的简洁直观
优点:只需在合适的时机开启enable;可以手动设置enable,掌握可响应时机
缺点:不直观
总结:个人还是推荐方案一和方案三,当然方案一想必是我们一直使用的手段,方案三提供了一种新的解决思路。如果方案四UIControl的分类可以自身获取到开启enable的时机,不失为暴力点击最完美的解决方案了,可以笔者能力有限,如果有读者有更好的解决方案,欢迎赐教。
二、cell的暴力点击
本着模仿UIButton的思路来解决cell的暴力点击,但是UITableView和UIBttoun的种种的不同,都未能找到较好的方案,只能粗暴一点的处理了。。。
暴力方案:使用标志符
{ // 新增cell点击标记 BOOL cellSelected; }
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ if (cellSelected) { return; }else{ cellSelected = YES; [self performSelector:@selector(didSelectRowAtIndexPath:) withObject:indexPath]; //[self performSelector:@selector(didSelectRowAtIndexPath:) withObject:indexPath afterDelay:2.0]; // 延迟执行,不推荐 } } -(void)didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ NSLog(@"%ld",indexPath.row); // 模拟事件处理,2秒之后再次响应 // do something dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ cellSelected = NO; }); }
点评:这种方法适用大部分的响应事件,包括按钮点击事件,tableView的点击事件,或者手势等,只是这样处理显得太粗暴,一点都不优雅,但是笔者现在能力有限,实在想不到其他比较好的方式了,555,如果读者有更好的解决方案,不吝赐教啊,感谢!
三、相关阅读
1、iOS 分类和扩展
2、iOS 运行时(runtime)
3、iOS UIButton点击事件传递参数的解决办法
相关文章推荐
- iOS - 解决短时间多次点击按钮,多次响应的问题
- ios 防止按钮快速点击造成多次响应的避免方法。
- ios 防止按钮快速点击造成多次响应的避免方法
- iOS解决按钮短时间内多次点击只触发一次事件方法
- ios 防止按钮快速点击造成多次响应的避免方法
- 关于jquerymobile的按钮点击在ios设备上响应慢的问题
- iOS 防止按钮多次点击造成多次响应的方法
- iOS开发中按钮多次响应问题解决方案
- ios 防止按钮快速点击造成多次响应的避免方法。
- ios 防止按钮快速点击造成多次响应的避免方法。
- ios 防止按钮快速点击造成多次响应的避免方法。
- ios 防止按钮快速点击造成多次响应的避免方法。
- iOS 防止按钮多次点击造成多次响应的方法
- ios 防止按钮快速点击造成多次响应的避免方法。
- ios 防止按钮快速点击造成多次响应的避免方法。
- ios 防止按钮快速点击造成多次响应的避免方法。
- ios 防止按钮快速点击造成多次响应的避免方法。
- iOS之a按钮重复点击的问题、cell重复点击的问题
- ios 防止按钮快速点击造成多次响应的避免方法。
- ios 防止按钮快速点击造成多次响应的避免方法。