iOS事件,原来如此

作者: muice | 来源:发表于2016-12-17 12:42 被阅读268次

精简地说:iOS事件分为传递和响应两个部分。

事件传递(建立传递链):

iOS系统检测到手指触摸(Touch)操作时会将其打包成一个UIEvent对象,并放入当前活动Application的事件队列,单例的UIApplication会从事件队列中取出触摸事件并传递给单例的UIWindow来处理,UIWindow对象首先会使用hitTest:withEvent:方法寻找此次Touch操作初始点所在的视图(View),即需要将触摸事件传递给其处理的视图,这个过程称之为hit-test view。
hittest的目的就是找到最终的传递链

hitTest:withEvent:流程如下:

  1. 先判断当前视图hidden=YES,userInteractionEnabled=NO,alpha<0.01等属性,如果满足其中之一,返回nil。
  2. 再看当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;
  3. 若返回NO,则hitTest:withEvent:返回nil;
  4. 若返回YES,则向当前视图的【一级子视图(subviews)递归发送】hitTest:withEvent:消息,所有子视图的遍历顺序是【从subviews数组的末尾向前遍历】,直到有子视图返回非空对象或者全部子视图遍历完毕;
  5. 若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;如所有子视图都返回非,则hitTest:withEvent:方法返回自身。

提醒:
hittest返回nil表示该条传递链已经终止,不是正确的传递链。
hittest返回非nil对象表示已经找到传递链的叶子节点,即找到正确的传递链。

hitTest:withEvent:遇到以下会返回nil。
1.hidden=YES的视图。
2.userInteractionEnabled=NO的视图(注意userInteractionEnabled是影响子视图事件传递,但不影响兄弟视图)
3.alpha<0.01的视图。
4.显示区域超过父视图bounds区域的视图。那么超出区域不能识别。当然,可以重写pointInside:withEvent:方法来识别。

结合例子分析:


例子.png

举例分析:用户点击了View D,下面结合上图介绍hit-test view的流程:
1、A是UIWindow的根视图,因此,UIWindwo对象会首先对A进行hit-test;
2、显然用户点击的范围是在A的范围内,因此,pointInside:withEvent:返回了YES,这时会继续检查A的子视图;
3、这时候会有两个分支,B和C:
C在subviews的末尾,先递归遍历C。点击的范围在C内,即C的pointInside:withEvent:返回YES;
4、这时候有D和E两个分支:
点击的范围不再E内,因此E的pointInside:withEvent:返回NO,对应的hitTest:withEvent:返回nil;
点击的范围在D内,即D的pointInside:withEvent:返回YES,由于D没有子视图,因此,D的hitTest:withEvent:会将D返回,再往回回溯,就是C的hitTest:withEvent:返回D--->>A的hitTest:withEvent:返回D。
即A->C->E(返回nil)->D(返回D)->C(返回D)->A(返回D)
至此,本次点击事件的第一响应者就通过响应者链的事件分发逻辑成功的找到了。
不难看出,这个处理流程有点类似二分搜索的思想,这样能以最快的速度,最精确地定位出能响应触摸事件的UIView。
另外hittest可能会被调用2-3次,这里请不要再hittest作业务相关操作,否则会导致执行多次。

事件响应(回溯响应链):

经过hittest后,我们已经找到了链尾【第一响应者】,这时候开始回溯响应操作。响应链的关系如图:
请注意:响应链在传递链的基础上增加了UIViewController。

UIResponder.png

在事件响应对象UIResponder(UIView和UIViewController都是继承UIResponder)中有对应的方法来分别处理这几个阶段的事件:
touchesBegan:NSArray<UITouch *>>withEvent:
touchesMoved:withEvent:
touchesEnded:withEvent:
touchesCancelled:withEvent:
Touch默认流程(以单击为例)是:从响应链叶子节点开始回溯,先是TouchBegan回溯,然后是TouchEnded回溯。

举例:对于触摸事件来说,UIApplication会首先把事件交给keyWindow,Window会将事件交给UIGestureRecognizer处理,如果UIGestureRecognizer识别了传递过来的事件,则交给相对应的target去处理,回溯终止,事件不会再传递。当然这里也可以重写touchBegan等方法手动让手势继续往superview传。如果UIGestureRecognizer并没有识别传递过来的事件(可能是没有视图添加手势,也可能手势识别不成功),事件会传递到视图树形结构

UIControlEvent:

其实要了解UIControlEvent,必须简单说一下UITouch和UIEvent事件,都是和触摸相关,UIEvent是一系列UITouch的集合,在IOS中负责响应触摸事件。

UIControl是UIView的子类,当然也是UIResponder的子类。UIControl是诸如UIButton、UISwitch、UITextField等控件的父类,它本身也包含了一些属性和方法。

UIControl对象采用了一种新的事件处理机制,将触摸事件转换成简单操作,其实就是重写了UIResponder的方法中(如touchBegan:withEvent)中,即事件不再往上回溯响应。这样方便了事件处理,而不用每次都重写TouchBegan方法。
UIResponder可以参考这篇文章UIKit: UIResponder
比如我点击一个UIButton,即使你未添加UIControlEventTouchUpInside,它的父类touchBegan也不会被调用。因为UIControl重写的方法touchBegan:withEvent并未调用[super touchBegan:withEvent]

UITapGestureRecognzier:

UITapGestureRecognzier其实就是对各类复杂触摸操作响应过程的一个封装。
在六种手势识别中,只有一种手势是离散手势,它就是UITapGestureRecognzier。离散手势的特点就是一旦识别就无法取消,而且只会调用一次手势操作事件(初始化手势时指定的触发方法)。换句话说其他五种手势是连续手势,连续手势的特点就是会多次调用手势操作事件,而且在连续手势识别后可以取消手势。【下图是手势状态图】

手势状态.png

分别以UITap和UIPan两种手势说明流程:
UITap:TouchBegan回溯->Tap->TouchCancelled回溯。
UIPan:TouchBegan回溯->TouchMoved多次回溯->UIPanBegan-TouchCancelled回溯->UIPanChanged多次->UIPanEnded。

总结:

  1. iOS事件流程分为寻找响应链和响应链回溯,其中响应链回溯部分和android类似。
  2. 为了事件响应处理的方便,苹果又推出了UIControlEvent和UITapGestureRecognzier。它们都是针对响应链回溯过程。
  3. UITapGestureRecognzier和UIControlEvent不同,UIControlEvent不会响应父类的TouchBegan等操作,而UITapGestureRecognzier会响应。

参考:
iOS开发系列--触摸事件、手势识别、摇晃事件、耳机线控

相关文章

  • iOS事件,原来如此

    精简地说:iOS事件分为传递和响应两个部分。 事件传递(建立传递链): iOS系统检测到手指触摸(Touch)操作...

  • iOS 事件以及手势的处理

    iOS 事件以及手势的处理 首先引用深入浅出iOS事件机制,iOS触摸事件处理详解,详解iOS触摸事件与手势识别三...

  • iOS 事件的传递响应机制

    iOS 中的事件 触摸事件 加速计事件 远程控制事件 iOS 中的触摸事件1、触摸事件发生,操作系统iOS会将此类...

  • iOS事件的响应者链

    iOS 事件响应者链 1 iOS中的事件 触摸事件 加速计事件 远程控制事件 在iOS中不是任何对象都能处理事件,...

  • 我们必须好好生活

    在某个阴天的下午,电视里放着重庆公交车坠江事件,忽然觉得生命原来如此脆弱,我们原来如此渺小…新闻里也时常有...

  • iOS 点击事件传递及响应

    1.iOS中的事件 iOS中的事件可以分为3大类型: 触摸事件加速计事件远程控制事件这里我们只讨论iOS中的触摸事...

  • iOS事件

    概述 iOS中事件有触摸事件、加速计事件、远程控制事件,下面以触摸事件为例研究下iOS事件相关的内容 UIResp...

  • iOS 响应链

    iOS开发 - 事件传递响应链iOS 响应者链,事件的传递事件传递之响应链Cocoa Touch事件处理流程--响...

  • 事件、事件响应链、手势分析

    一.事件 1.iOS三大事件包含触摸事件,设备移动事件,远程控制事件 2.iOS规定只有继承UIResponder...

  • 《iOS事件触摸与手势》

    iOS事件触摸与手势 一、事件分发处理【由外到内】在iOS中发生触摸后,事件会加到UIApplication事件队...

网友评论

    本文标题:iOS事件,原来如此

    本文链接:https://www.haomeiwen.com/subject/iiogmttx.html