本文共 1560 字,大约阅读时间需要 5 分钟。
前言
iOS 中对手势响应事件的定义很丰富(参考),最常用的是点击手势,若不做一些配置处理,你可能会遇到很尴尬的问题,如一个页面两个弹窗重叠,一个页面被Push了多次等。让我们一起探讨下,怎么避开这些坑。“同时”:物理世界中,事件的发生,并不存在绝对上的同时。
注意:我在下文描述时,用的是点击手势和响应区域,其实,UIView的子类都可以添加点击手势和响应事件,与点击UIbutton并响应事件本质上是相同的。
先抛出一些小结论:
1、点击事件之间是可以“同时”共存,并能分别“同时”响应的。(同时点击两个响应区域分别响应)
2、线程被阻塞时,点击手势也是可以缓存的,并在线程通畅后统一响应。(单个响应区域的重复点击并重复响应)。
发现问题 1、当一个页面中存在两个以上可点击的响应区域时,基本都存在“同时”点击,分别“同时”响应的问题,尤其是响应事件分别为弹出窗口或跳转到另一个页面时,窗口存在重叠效果,最为突出。
2、当主线程被阻塞时,单个响应区域的重复点,会造成重复响应,如一个页面被Push了多次。
概述
- setExclusiveTouch 是UIView的一个属性,默认为NO(不互斥),设置UIView 接收手势的互斥性为YES,防止多个响应区域被“同时”点击,“同时”响应的问题。
- 可以通过 [[UIView appearance] setExclusiveTouch:YES]; UIImageView ,UILabel等,都可以添加手势,响应方式和UIButton 相同。全局设置响应区域的点击手势的互斥,是有效的。但使用此方法时,在iOS 8.0~iOS8.2(目前仅在该版本下发现问题)下会引起崩溃。
问题分析:
- UIView虽然遵守了UIAppearance 和 UIAppearanceContainer协议(支持UIAppearance协议的类可以访问appearance selector ,它为receiver返回appearance proxy,我么可以给proxy发一些消息),并能正常调用[[UIView appearance] setExclusiveTouch:YES]; (无警告,无报错),但 exclusiveTouch 并没有被声明UI_APPEARANCE_SELECTOR,低版本上可能是无效的,甚至会抛出 unknown selector 异常,引起崩溃。
解决方案:
- 方案一:setExclusiveTouch:YES 可以通过单独设置或批量设置UIView及其子类的手势互斥性,针对具体的使用场景,对个别的UIbutton等单独设置。这样可以解决主要的问题:点击两个不同的响应区域 出现两个弹窗或Push(present)页面的情况。但需要很多处设置,可能会有遗漏。
- 方案二:给UIView创建一个分类UIView+ExclusiveTouch,通过runtime 运行机制,给UIView 补充一个属性,如ygExclusiveTouch,遵守UIAppearance和UIAppearanceContainer协议,并对属性使用UI_APPEARANCE_SELECTOR 声明 ,并实现getter/setter方法,要在set方法中添加self.exclusiveTouch = ygExclusiveTouch;设置属性。
综述
- 在AppDelegate的didFinishLaunchingWithOptions方法最前面(创建视图之前)调用分类中的方法设置ygExclusiveTouch。可以实现全局设置点击区域的互斥性,是否能完全解决iOS 8.0~iOS8.2下会引起崩溃,需要验证。综合考虑,使用了方案一。后续抽时间,再验证完善这一块。
转载地址:http://pkdws.baihongyu.com/