您的位置:首页 > 移动开发 > IOS开发

【iOS开发】事件处理之响应链(二)

2016-06-08 16:42 357 查看

事件传递:响应链

当你设计你的应用程序,很可能想要得到事件的动态响应。例如,可能会出现一个触摸,有多个对象响应,因此你必须要决定是哪个对象要响应和处理此触摸事件。

当用户生成的事件发生时,UIKit中创建包含处理该事件所需要的信息的事件对象。然后,它会在事件对象主动应用程序的事件队列。为触摸事件时,该对象是一组包装在触摸的UIEvent对象。对于运动事件,该事件对象取决于您所使用的框架和什么类型的运动事件是你感兴趣的内容。

该事件会沿着特定路径传递,直到它被输送到一个可以处理它的对象。首先,单例[b]UIApplication对象从队列的顶部发生的事件并分派它用于处理。通常情况下,它发送事件到应用程序的key window object(主窗口对象),由它来进行处理初始对象。初始对象取决于事件类型。[/b]

[b]1.Touch events。对于触摸事件,窗口对象首先尝试将事件交给触摸发生时的视图。这一视图被称为hit-test视图。找到hit-test视图的过程被称为hit-testing详细参考官方文档。[/b]

[b]2.Motion and remote control events。 对于这些事件,窗口对象发送摇动动作或远程遥控事件给能进行处理这些事件的第一个响应者。查看第一响应者具体信息,请参考官方文档。[/b]

这些事件的路径的最终目标是要找到一个对象,该对象能够处理和对事件作出响应。因此,UIKit中首先发送事件到最适于处理该事件的对象。对于触摸事件,这个对象是hit-test视图,对于其他事件,该对象是第一个响应者。下面的章节详细介绍[b]hit-test视图第一响应者对象。[/b]

视图的某一个地方发生触摸返回一个Hit-Testing

iOS的使用[b]hit-testing来确认某个视图是否被触摸。Hit-testing包括检查触摸是否发生在任何相关视图对象的范围之内。如果是,它递归地检查所有视图的子视图。在包含触摸点视图层次最低的视图成为hit-test视图。iOS的确认hit-test视图后,它会传递触摸事件到该视图进行处理。[/b]

举例说明,如图2-1假设用户触摸view E。iOS通过hit-test视图通过以下步骤在子视图中进行查找:

1. 触摸是位于A的范围内,因此会检查子视图B和C.

2. 触摸不在视图B的范围内,但在视图C的范围内,因此,它检查子视图D和E

3. 触摸不在视图D的范围内,但它在图E的范围内,

视图E是在包含触摸视图以内,层次最低的视图,因此它成为hit-test视图。



图2-1 Hit-testing视图:子视图中被点击的视图

该[b]hitTest:withEvent:方法返回一个给定的点击测试视图的CGPointUIEvent。该hitTest:withEvent:方法首先调用pointInside:withEvent:方法本身的方法。如果点传递到hitTest:withEvent:方法认为该点击在某个视图的边界内,则pointInside:withEvent:方法返回YES。然后,该方法递归地调用hitTest:withEvent:方法对每一个子视图返回YES。[/b]

如果点传递到[b]hitTest:withEvent:方法而不在视图的边界内,以第一次调用pointInside:withEvent:方法返回NO,该点被忽略,则hitTest:withEvent:方法返回无。如果一个子视图返回NO,则该视图的全部子视图都将停止传递。如果子视图的可能出现这种情况(这种情况指:该视图通过调用pointInside:withEvent:方法,返回NO),则clipsToBounds属性设置为NO。[/b]

注: 触摸对象的生命周期与它的hit-test视图相关联,即使触摸比较晚才离开视图。

响应链是由响应对象组成

多种类型的事件依赖于一个响应链的事件传递。响应链是一系列响应对象之间的相互链接。响应链开始于第一响应者,结束于应用对象。如果第一响应者不能处理事件时,它转发该事件到响应链中的下一个响应者。

一个响应者对象是一个对象,可以响应和处理事件。[b]UIResponder类是所有响应者对象的基类,它定义编程接口不仅可以处理事件也可以响应常见的响应者行为。例如:UIApplicationUIViewControllerUIView这些类是响应者,这意味着所有的View和大部分的Controller是响应者。需要注意的是Core Animation layers(核心动画层)不能成为响应者。[/b]

注意:Layer 不能成为响应者,View和Controller能成为响应者。

第一响应者默认被指定为第一个接收事件的对象。通常情况下,第一响应者是一个View(视图)对象。一个对象要成为第一响应者要完成以下两条件:

1 .重写[b]canBecomeFirstResponder方法,返回YES。[/b]

2. 接收[b]becomeFirstResponder消息。如果有必要,一个对象可以自行发送此消息。[/b]

注: 一个对象要想成为第一个响应者,必须保证该对象已经被创建。例如,您通常在viewDidAppear:方法中调用becomeFirstResponder。如果您尝试在viewWillAppear:的时候,分配第一个响应者,则becomeFirstResponder方法返回NO,因为此时对象还没被创建。

Events(事件)不是依赖于响应链的唯一对象。响应者链在以下所有情况中也使用:

Touch events(触摸事件)。如果hit-test视图无法处理触摸事件。则该事件从hit-test视图开始,在响应者链中终止传递。

Motion events(运动事件)。UIKit中的摇一摇动作,第一响应者必须实现UIResponder类中的motionBegan:withEvent:方法或motionEnded:withEvent:方法,正如Detecting Shake-Motion Events with UIEvent 文档中所描述的。

Remote control events(远程遥控事件)。处理远程遥控事件,第一个响应者必须实现UIResponder类中的remoteControlReceivedWithEvent:方法。

Action messages(动作信息)。当用户操纵一个控件时,例如UIButtonUISwitch,如果这些控件不存在响应方法,该消息将由第一个响应者通过响应者链,传递到具体能响应该事件的控件上。

Editing-menu messages(编辑菜单消息)。当用户点击编辑菜单中的命令,iOS采用了响应者链找到实现该方法的对象(如剪切,复制,粘贴)。欲了解更多信息,请参阅 Displaying and Managing the Edit Menu,CopyPasteTile(剪切板)。

Text editing(文本编辑)。当用户点击文本字段或文本视图,该视图自动成为第一个响应者。默认情况下,虚拟键盘和显示文本字段或文本视图编辑成为关注的焦点。如果它是适合您的应用程序,你可以显示一个定制输入视图,而不是键盘。您还可以添加自定义输入,以便作出响应的对象。欲了解更多信息,请参阅 Custom Views for Data Input

注: UIKit中自动设置文本字段或文本观点,即用户点击成为第一个响应者; 应用程序必须显式设置与所有其他第一响应者对象becomeFirstResponder方法。

响应链按照特定的传送路径

如果初始对象或者hit-test视图或第一响应者不能处理一个事件,UIKit将通过响应链中nextResponder来传递该事件。各应答器决定是否自己处理该事件或通过调用其传递给它自己的下一个应答器的nextResponder 方法来继续传递,这个过程直到一个响应者对象终止处理事件或已经没有更多的响应者而结束。

当iOS检测到事件并将其传递到初始对象,该视图响应链按顺序开始进行。初始视图可以第一次处理该事件。图2-2显示了两个应用程序配置两个不同的事件传递路径。一个应用程序的事件传递路径取决于它的具体结构,但所有事件传递路径,采用相同的启发法。



图2-2 iOS上的响应链

左边的应用程序,该事件遵循此路径:

初始视图试图处理该事件或消息。如果它不能处理这个事件,它传递事件到SuperView,因为初始视图是它的视图控制器的视图层次最顶部的视图。

SuperView尝试处理该事件。如果SuperView不能处理这个事件,它传递该事件到它的SuperView,因为它仍然不是视图层次最顶部的视图。

视图控制器中最上层的视图尝试处理该事件。如果最上层的视图不能处理这个事件,它传递该事件到它的视图控制器。

视图控制器试图处理该事件,如果不能,将事件传递到窗口。

如果窗口对象不能处理这个事件,它传递事件到Application

如果Application对象不能处理这个事件,它丢弃该事件。

右边的应用程序遵循稍有不同的路径,但所有事件传递路径,请按照下列路径:

初始视图传递事件,直到该事件到达它的视图控制器的视图层次最顶端的视图。

最顶端的视图传递事件到其视图控制器。

视图控制器将事件传递到其最上面的视图的。步骤1-3重复,直到事件到达根视图控制器。


根视图控制器传递事件到窗口对象。

窗口对象传递事件到应用程序对象。

重要提示: 如果您实现一个自定义视图来处理远程遥控事件,行动的消息,摇一摇事件,或编辑菜单中的邮件,不转发事件或消息通过nextResponder直接把它送到响应链中。相反,调用超类实现当前事件的处理方法,通过UIKit处理响应链方式,方便的为您服务。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: