同时点击手势深度优化处理 setExclusiveTouch

来源:互联网 发布:linux系统的基本命令 编辑:程序博客网 时间:2021/11/29 07:12

前言

iOS 中对手势响应事件的定义很丰富(参考iOS七种手势),最常用的是点击手势,若不做一些配置处理,你可能会遇到很尴尬的问题,如一个页面两个弹窗重叠,一个页面被Push了多次等。让我们一起探讨下,怎么避开这些坑。“同时”:物理世界中,事件的发生,并不存在绝对上的同时。

注意:我在下文描述时,用的是点击手势和响应区域,其实,UIView的子类都可以添加点击手势和响应事件,与点击UIbutton并响应事件本质上是相同的。

先抛出一些小结论:

1、点击事件之间是可以“同时”共存,并能分别“同时”响应的。(同时点击两个响应区域分别响应)

2、线程被阻塞时,点击手势也是可以缓存的,并在线程通畅后统一响应。(单个响应区域的重复点击并重复响应)。

发现问题

1、当一个页面中存在两个以上可点击的响应区域时,基本都存在“同时”点击,分别“同时”响应的问题,尤其是响应事件分别为弹出窗口或跳转到另一个页面时,窗口存在重叠效果,最为突出

2、当主线程被阻塞时,单个响应区域的重复点,会造成重复响应,如一个页面被Push了多次。

概述

  1. setExclusiveTouch  是UIView的一个属性,默认为NO(不互斥),设置UIView 接收手势的互斥性为YES,防止多个响应区域被“同时”点击,“同时”响应的问题。
  2. 可以通过  [[UIView appearance] setExclusiveTouch:YES]; UIImageView ,UILabel等,都可以添加手势,响应方式和UIButton 相同。全局设置响应区域的点击手势的互斥,是有效的。但使用此方法时,在iOS 8.0~iOS8.2(目前仅在该版本下发现问题)下会引起崩溃。

问题分析:

  1. UIView虽然遵守了UIAppearance 和 UIAppearanceContainer协议(支持UIAppearance协议的类可以访问appearance selector ,它为receiver返回appearance proxy,我么可以给proxy发一些消息),并能正常调用[[UIView appearance] setExclusiveTouch:YES];  (无警告,无报错),但 exclusiveTouch 并没有被声明UI_APPEARANCE_SELECTOR,低版本上可能是无效的,甚至会抛出 unknown selector 异常,引起崩溃。

解决方案:

  1. 方案一:setExclusiveTouch:YES 可以通过单独设置或批量设置UIView及其子类的手势互斥性,针对具体的使用场景,对个别的UIbutton等单独设置。这样可以解决主要的问题:点击两个不同的响应区域 出现两个弹窗或Push(present)页面的情况。但需要很多处设置,可能会有遗漏。
  2. 方案二:给UIView创建一个分类UIView+ExclusiveTouch,通过runtime 运行机制,给UIView 补充一个属性,如ygExclusiveTouch,遵守UIAppearance和UIAppearanceContainer协议,并对属性使用UI_APPEARANCE_SELECTOR 声明 ,并实现getter/setter方法,要在set方法中添加self.exclusiveTouch = ygExclusiveTouch;设置属性。

综述

  1. AppDelegatedidFinishLaunchingWithOptions方法最前面(创建视图之前)调用分类中的方法设置ygExclusiveTouch。可以实现全局设置点击区域的互斥性,是否能完全解决iOS 8.0~iOS8.2下会引起崩溃,需要验证。综合考虑,使用了方案一。后续抽时间,再验证完善这一块。
项目demo