一、触摸事件的事件传递
触摸事件的传递方向是 由内至外(外:指所触摸的最外层视图)
触摸开始后,系统会把事件加入到UIApplication事件队列。而后UIApplication会从事件队列中取出最前面的事件分发处理。先分发给程序的主窗口,让后主窗口调用
hitTest: withEvent:
方法,查找用户所点击的视图。1.1、在最内层视图(key window 视图)上调用 pointInside:withEvent: 方法来判断事件触摸点是否在当前视图内。如果返回NO,则hitTest:withEvent: 方法返回nil,表明用户的触摸点不再此视图上。
1.2、如果返回YES,那么当前视图会向所有子视图发送hitTest:withEvent: 方法。
1.3、子视图仍然按照hitTest:withEvent: 和 pointInside:withEvent:结合的方法来查找所点击的视图。
1.4、如果最终都没有找到所点击的视图,则hitTest:withEvent:最后返回的仍然是nil。事件传递结束。
1.5、如果最终查找到所点击的视图,则hitTest:withEvent:最后返回的是所点击的视图对象。然后准备进行事件响应。
重要事例:当用户点击的point超出父视图(B)的frame时。程序最终找不到所点击的视图,hitTest:withEvent:返回是nil。
当程序查找到父视图(B)的时候,因为用户所点击的点处于父视图(B)的外面。pointInside:withEvent: 方法判断结果是触摸点不在此父视图(B)上,pointInside:withEvent: 方法返回的结果始终为NO,则父视图不会再向子视图发送hitTest:withEvent:方法。
二、触摸事件的响应者链条
响应者链条的传递方向是 由外至内
2.1、事件传递查找到用户点击的视图(C)后,当前视图(C)是否能够响应触摸事件(处理触摸事件)。
2.2、如果不能响应触摸事件,则交给当前视图(C)的父视图来响应。
2.3、如果父视图不能响应触摸事件,则由父视图的父视图来响应。
2.4、若最后谁都不对此触摸事件做处理,则丢弃此事件。
一般来说,如果子视图响应了触摸事件后,父视图就不会再响应此触摸事件。
重要:
但是系统API判断子视图是否响应了触摸事件的方法。是由是否重写了
touchesBegan: withEvent:
方法来判断的。如果您没有重写touchBegan:withEvent:方法,即使重写了剩余的其他三个touch方法,系统仍然认为子视图没有响应触摸事件而会一直向父视图响应下去。