IOS 应用事件的传递分析

作者:朱克锋

邮箱:[email protected]

转载请注明出处:http://blog.csdn.net/linux_zkf


系统将事件按照特定的路径传递给可以对其进行处理的对象。当用户触摸设备屏幕时,iPhone OS会将它识别为一组触摸对象,并将它们封装在一个UIEvent对象中,放入当前应用程序的事件队列中。事件对象将特定时刻的多点触摸序列封装为一些触摸对象。负责管理应用程序的UIApplication单件对象将事件从队列的顶部取出,然后派发给其它对象进行处理。典型情况下,它会将事件发送给应用程序的键盘焦点窗口—即拥有当前用户事件焦点的窗口,然后代表该窗口的UIWindow对象再将它发送给第一响应者进行处理。
应用程序通过触碰测试(hit-testing)来寻找事件的第一响应者,即通过递归调用视图层次中视图对象的hitTest:withEvent:方法来确认发生触摸的子视图。触摸对象的整个生命周期都和该视图互相关联,即使触摸动作最终移动到该视图区域之外也是如此。“事件处理技巧”部分对触碰测试在编程方面的一些隐含意义进行讨论。
UIApplication对象和每个UIWindow对象都在sendEvent:方法(两个类都声明了这个方法)中派发事件。由于这些方法是事件进入应用程序的通道,所以,您可以从UIApplication或UIWindow派生出子类,重载其sendEvent:方法,实现对事件的监控或执行特殊的事件处理。但是,大多数应用程序都不需要这样做。
响应者对象和响应者链
响应者对象是可以响应事件并对其进行处理的对象。UIResponder是所有响应者对象的基类,它不仅为事件处理,而且也为常见的响应者行为定义编程接口。UIApplication、UIView、和所有从UIView派生出来的UIKit类(包括UIWindow)都直接或间接地继承自UIResponder类。
第一响应者是应用程序中当前负责接收触摸事件的响应者对象(通常是一个UIView对象)。UIWindow对象以消息的形式将事件发送给第一响应者,使其有机会首先处理事件。如果第一响应者没有进行处理,系统就将事件(通过消息)传递给响应者链中的下一个响应者,看看它是否可以进行处理。
响应者链是一系列链接在一起的响应者对象,它允许响应者对象将处理事件的责任传递给其它更高级别的对象。随着应用程序寻找能够处理事件的对象,事件就在响应者链中向上传递。响应者链由一系列“下一个响应者”组成,其顺序如下:
    1.    第一响应者将事件传递给它的视图控制器(如果有的话),然后是它的父视图。
    2.    类似地,视图层次中的每个后续视图都首先传递给它的视图控制器(如果有的话),然后是它的父视图。
    3.    最上层的容器视图将事件传递给UIWindow对象。
    4.    UIWindow对象将事件传递给UIApplication单件对象。
如果应用程序找不到能够处理事件的响应者对象,则丢弃该事件。
响应者链中的所有响应者对象都可以实现UIResponder的某个事件处理方法,因此也都可以接收事件消息。但是,它们可能不愿处理或只是部分处理某些事件。如果是那样的话,它们可以将事件消息转送给下一个响应者,方法大致如下:
 
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
       
    UITouch* touch = [touches anyObject];
       
    NSUInteger numTaps = [touch tapCount];
       
    if (numTaps < 2) {
       
        [self.nextResponder touchesBegan:touches withEvent:event];
       
   } else {
       
        [self handleDoubleTap:touch];
       
   }
       
}
    
请注意:如果一个响应者对象将一个多点触摸序列的初始阶段的事件处理消息转发给下一个响应者(在touchesBegan:withEvent:方法中), 就应该同样转发该序列的其它事件处理消息。
动作消息的处理也使用响应者链。当用户对诸如按键或分页控件这样的UIControl对象进行操作时,控件对象(如果正确配置的话)会向目标对象发送动作消息。但是,如果目标对象被指定为nil,应用程序就会像处理事件消息那样,把该动作消息路由给第一响应者。如果第一响应者没有进行处理,再发送给其下一个响应者,以此类推,将消息沿着响应者链向上传递。
调整事件的传递
UIKit为应用程序提供了一些简化事件处理、甚至完全关闭事件流的编程接口。下面对这些方法进行总结:
    ▪关闭事件的传递。缺省情况下,视图会接收触摸事件。但是,您可以将其userInteractionEnabled属性声明设置为NO,关闭事件传递的功能。隐藏或透明的视图也不能接收事件。
    ▪在一定的时间内关闭事件的传递。应用程序可以调用UIApplication的beginIgnoringInteractionEvents方法,并在随后调用endIgnoringInteractionEvents方法来实现这个目的。前一个方法使应用程序完全停止接收触摸事件消息,第二个方法则重启消息的接收。某些时候,当您的代码正在执行动画时,可能希望关闭事件的传递。
    ▪打开多点触摸的传递。 缺省情况下,视图只接收多点触摸序列的第一个触摸事件,而忽略所有其它事件。如果您希望视图处理多点触摸,就必须使它启用这个功能。在代码或Interface Builder的查看器窗口中将视图的multipleTouchEnabled属性设置为YES,就可以实现这个目标。
    ▪将事件传递限制在某个单独的视图上。 缺省情况下,视图的exclusiveTouch属性被设置为NO。将这个属性设置为YES会使相应的视图具有这样的特性:即当该视图正在跟踪触摸动作时,窗口中的其它视图无法同时进行跟踪,它们不能接收到那些触摸事件。然而,一个标识为“独占触摸”的视图不能接收与同一窗口中其它视图相关联的触摸事件。如果一个手指接触到一个独占触摸的视图,则仅当该视图是窗口中唯一一个跟踪手指的视图时,触摸事件才会被传递。如果一个手指接触到一个非独占触摸的视图,则仅当窗口中没有其它独占触摸视图跟踪手指时,该触摸事件才会被传递。

    ▪将事件传递限制在子视图上。一个定制的UIView类可以通过重载hitTest:withEvent:方法来将多点触摸事件的传递限制在它的子视图上



你可能感兴趣的:(ios,编程,测试,iPhone,UIView,interface)