http://blog.csdn.net/chun799/article/details/8194893
接下文。。。
当你设计App时你可能需要动态的响应事件。例如,一个触摸事件可能发生在屏幕上不同的对象中,你需要决定哪个对象来响应这个给定的事件,理解对象如何接收事件。
当用户触发的一个事件发生,UIKit会创建一个包含要处理的事件信息的事件对象。然后她会将事件对象放入active app’s(应用程序对象,每个程序对应唯一一个)事件队列。对于触摸事件,事件对象就是UIevent对象封装的一系列触摸集合。对于动作事件,这个事件对象依赖于使用的framework和你关心哪种动作事件。
事件通过特殊的路径传递直到被传递到一个可以处理该事件的对象。首先,单例的UIApplication对象从顶层的队列中获取事件,然后分发。典型的,它将事件发送到App的关键window(key window)对象,window则为了处理该事件而发送它到初始化对象(initial object),这个初始化对像依靠事件类型。
事件传递路径的最终目的时找出能处理和响应该事件的对象。因此,UIKit给适合处理该事件的对象发送事件。对于触摸事件,这个对象就是hit-test view,对于其他事件,这个对象就是第一个响应器(first responder)。下面的章节解释了hit-test view和first responder对象是如何被确定的。
iOS使用hit-testing寻找触摸的view。 Hit-Testing通过检查触摸点是否在关联的view边界内,如果在,则递归地(recursively)检查该view的所有子view。在层级上处于lowest(我理解就是离用户最近的view)且边界范围包含触摸点的view成为hit-test view。确定hit-test view后,它传递触摸事件给该view。
举例说明,假设用户触摸了图中的view E。iOS通过如下顺序查找hit-test view。
View E是这个层级上处于lowest的view的边界范围包含触摸点,所以它成为了hit-test view。
hitTest:withEvent:方法通过传递进来CGPoint和UIEvent返回hit test view。该方法调用pointInside:withEvent:方法,如果传入hitTest:withEvent:的point在view的边界范围内,则pointInside:withEvent:返回YES。然后,这个方法会在view的所有子view中递归的调用hitTest:withEvent:。
如果传入hitTest:withEvent:的point在view的边界范围内,则pointInside:withEvent:返回NO。这个point会被忽略,hitTest:withEvent:返回nil。如果一个子view返回NO,则它所在的view的层级上的分支的子view都会被忽略。
Hit-test view是处理触摸事件的第一选择,如果hit-test view不能处理事件,该事件将从事件响应链中寻找响应器,直到系统找到一个处理事件的对象。具体见“The Responder Chain Is Made Up of Responder Objects”。
一些类型的事件的传递依赖响应器链。响应器链(responder chain)是一系列相关的响应器对象。它开始于第一个响应器终止于应用对象(application object)。如果第一个responder不处理事件,则会根据responder chain将event传递给下一个responder。
Responder object,即可以响应和处理事件的对象。UIResponder类是所有responder对象的基类,它定义了动态的接口,不仅处理事件也包括处理响应行为。包括UIApplication,UIViewController,和UIView类都是responder,这意味着所有view和大部分关键的controller对象都是responder。足以Core Animation layers不是responders。
First responder被设计来第一个接收事件。典型的,first responder是一个view object。之所以成为第一个responder由于两个原因:
。。。
如果初始化对象(initial object)—— 即hit-test view或者first responder —— 不处理事件,UIKit会将事件传递给responder chain的下一个responder。每个responder决定它是传递事件还是通过nextResponder方法传递给它的下一个responder。这个操作继续直到一个responder处理event或者没有responder了。
Responder chain 序列在iOS确定一个事件并将它传递给initial object(通常是view)时开始。所以initial view有处理事件的第一个机会。下图描述了两个不同的事件传递路径(因为不同的app 设置)。一个App的事件传递路径由app特殊的构成决定,但事件传递路径会遵守相同的规则。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
返回在层级上离当前view最远(离用户最近)且包含指定的point的view。
关于hitTest方法的解释见hitTest:withEvent:方法流程
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
返回boolean值指出receiver是否包含指定的point。
如下调用:手动指定当前view不响应事件
1
2 3 4 5 6 7 |
|
事件的传递和响应分两个链: