1、原理
在应用程序成功启动后,应用程序就开始由外部事件进行驱动。应用程序不断获取事件,并作出响应并更新用户界面,然后等待下一个事件。这对事件进行循环响应的整个机制,称为主要事件循环,由一个全局应用程序对象(一个UIApplication实例)进行管理。
在事件循环中最重要的事件之一就是用户与设备的交互操作。在iOS设备中,用户对设备的操作可以通过多种方式,如点击屏幕或者晃动设备等。iOS操作系统会解析这些操作,并将响应通知应用做出相应。对这些操作进行更加自然和直观的相应可以增强应用的用户友好度。在ios中,这些响应以事件Event的方式实现。在ios中,一般把事件分为三大类:①触控事件,用于处理用户对屏幕的多点触控操作;②运动事件,用户处理设备的移动、摇晃和方向变换等操作;③遥控事件,用户处理用户的遥控设备对ios设备的操作(如线控耳机等)。
封装了三种事件的UIKit类——UIEvent:UIEvent类封装了事件的类型之外,还封装了应用对事件的响应信息。每一次操作发生时操作系统都会发出一个UIEvent对象,每个对象都会使用类型(type)和子类型(subtype)来表示事件的类型。
2、触控事件的处理:
通过重写以下方法监听触控事件:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
在以上函数中,NSSet类型的参数touches代表触控屏幕有几根手指,每一个元素都是一个UITouch实例,可以调用tapCount方法获取短时间内的点击次数。除此之外,还有window、view、phase等属性,分别表示触控发生的窗口、视图和周期(开始、移动、结束、取消)。
UITouch类的方法主要有:
- (CGPoint)locationInView:(UIView *)view;//返回触控相对于视图的坐标点 - (CGPoint)previousLocationInView:(UIView *)view;//返回前一个触控的坐标点
3、 消息传递的响应链
用户产生的事件发生之后,UIKit会产生一个包含相应的处理所需信息的event对象,并将其放入活动app的事件队列中。如果是触控事件,对象封装在UIEvent中;如果是运动事件,对象封装根据运动类型和采用框架的不同而不同。一个事件沿事件传递路径传递,直到找到一个可以处理当前事件的对象为止。首先,UIApplication单例对象从事件队列的顶部取出一个事件,并通常传送至窗口对象处理。对于触控事件,窗口对象首先尝试将其传送至触控发生的视图对象以供处理;对于运动事件和遥控事件,窗口对象将其发送到定义的第一响应者对象处理。
(1)查找触控事件的响应:iOS通过“触击检测”(hit-testing)机制判断发生触控的视图。
众所周知,屏幕上的视图由父视图和子视图构成了一个树形的结构,我们称为视图树。触击检测通过自顶向下检测触控发生在哪一个视图范围内,最终确定包含触控发生点并且在视图树中最低层的视图为目标视图。给定视图上的一个点(CGPoint)和事件(UIEvent),可以使用 hitTest:withEvent: 实现该功能,返回相应的目标视图。
(2)响应链由响应者对象构成:
响应链由第一响应者开始,终于应用对象(UIApplication object),由响应者对象组成。在iOS中,响应者对象由UIResponder类实现,该类用于实现事件响应以及其他的响应操作,是UIApplication、UIViewController和UIView等类的基类。第一响应者是其中第一个接受事件的对象,通常为一个视图对象。某对象称为第一响应者,需要完成两部:第一重写
canBecomeFirstResponder方法并返回YES;第二调用 becomeFirstResponder。
响应链可以处理下面几种问题:
- 触控事件:如果触击检测返回的视图不能处理该事件,事件就会沿着响应链向上传递直到某对象可以处理该事件;
- 运动事件:第一响应者必须实现UIResponder类的motionBegan:withEvent:和motionEnded:withEvent:方法来处理这类事件;
- 遥控事件:第一响应者需实现 remoteControlReceivedWithEvent:方法;
- Action消息:如果某个控件(如按钮)被点击,而且该控件没有设置target,那么这个消息就将沿着响应链传递;
- 编辑菜单消息:点击编辑菜单的命令后,iOS使用响应链寻找可以实现编辑命令(如剪切复制粘贴等)的对象;
- 文本编辑:当点击文本编辑框时,该对象称为第一响应者,同时默认弹出虚拟键盘。可以通过resignFirstResponder消息放弃第一响应者,可以关闭虚拟键盘并结束编辑状态。只有文本编辑框可以在用户点击时自动称为第一响应者,其他对象必须调用becomeFirstResponder方法来称为第一响应者。
(3)响应链的响应顺序:
如果响应链的第一个元素(触击检测返回视图,或者第一响应者)不能处理事件,那么事件将会传递至响应链的第二个元素。如果响应链的某个元素不能处理该事件,会将其继续向下传递直到响应链上没有可以处理的对象为止。
当iOS检测到一个事件时,响应链开始工作,将事件传递给第一个元素(通常为某视图,即初始视图),该元素有最优先处理事件的机会。通常情况下,事件传递的顺序为:初始视图尝试处理事件,如果不能处理则传递给其父视图;父视图尝试处理事件,如果不能处理则传递给其父视图,直至顶层视图,如果顶层视图不能处理,则传递给当前视图控制器处理;如果视图控制器不能处理,则传递给窗口对象处理;若窗口对象不能处理,则传递给应用单例对象处理;最后若应用对象不能处理,则放弃该事件。