1、事件分类html
对于IOS设备用户来讲,他们操做设备的方式主要有三种:触摸屏幕、晃动设备、经过遥控设施控制设备。对应的事件类型有如下三种:前端
一、触屏事件(Touch Event)ios
二、运动事件(Motion Event)数组
三、远端控制事件(Remote-Control Event)网络
今天以触屏事件(Touch Event)为例,来讲明在Cocoa Touch框架中,事件的处理流程。首先不得不先介绍响应者链这个概念:app
2、响应者链(Responder Chain)框架
先来讲说响应者对象(Responder Object),顾名思义,指的是有响应和处理事件能力的对象。响应者链就是由一系列的响应者对象构成的一个层次结构。ide
UIResponder是全部响应对象的基类,在UIResponder类中定义了处理上述各类事件的接口。咱们熟悉的UIApplication、 UIViewController、UIWindow和全部继承自UIView的UIKit类都直接或间接的继承自UIResponder,因此它们的实例都是能够构成响应者链的响应者对象。图一展现了响应者链的基本构成:函数
图一oop
从图一中能够看到,响应者链有如下特色:
一、响应者链一般是由视图(UIView)构成的;
二、一个视图的下一个响应者是它视图控制器(UIViewController)(若是有的话),而后再转给它的父视图(Super View);
三、视图控制器(若是有的话)的下一个响应者为其管理的视图的父视图;
四、单例的窗口(UIWindow)的内容视图将指向窗口自己做为它的下一个响应者
须要指出的是,Cocoa Touch应用不像Cocoa应用,它只有一个UIWindow对象,所以整个响应者链要简单一点;
五、单例的应用(UIApplication)是一个响应者链的终点,它的下一个响应者指向nil,以结束整个循环。
3、事件分发(Event Delivery)
第一响应者(First responder)指的是当前接受触摸的响应者对象(一般是一个UIView对象),即表示当前该对象正在与用户交互,它是响应者链的开端。整个响应者链和事件分发的使命都是找出第一响应者。
UIWindow对象以消息的形式将事件发送给第一响应者,使其有机会首先处理事件。若是第一响应者没有进行处理,系统就将事件(经过消息)传递给响应者链中的下一个响应者,看看它是否能够进行处理。
iOS系统检测到手指触摸(Touch)操做时会将其打包成一个UIEvent对象,并放入当前活动Application的事件队列,单例的UIApplication会从事件队列中取出触摸事件并传递给单例的UIWindow来处理,UIWindow对象首先会使用hitTest:withEvent:方法寻找这次Touch操做初始点所在的视图(View),即须要将触摸事件传递给其处理的视图,这个过程称之为hit-test view。
UIWindow实例对象会首先在它的内容视图上调用hitTest:withEvent:,此方法会在其视图层级结构中的每一个视图上调用pointInside:withEvent:(该方法用来判断点击事件发生的位置是否处于当前视图范围内,以肯定用户是否是点击了当前视图),若是pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操做发生的位置,这个视图也就是要找的hit-test view。
hitTest:withEvent:方法的处理流程以下:
首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;
若返回NO,则hitTest:withEvent:返回nil;
若返回YES,则向当前视图的全部子视图(subviews)发送hitTest:withEvent:消息,全部子视图的遍历顺序是从最顶层视图一直到到最底层视图,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者所有子视图遍历完毕;
若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
如全部子视图都返回非,则hitTest:withEvent:方法返回自身(self)。
图二
加入用户点击了View E,下面结合图二介绍hit-test view的流程:
一、A是UIWindow的根视图,所以,UIWindwo对象会首相对A进行hit-test;
二、显然用户点击的范围是在A的范围内,所以,pointInside:withEvent:返回了YES,这时会继续检查A的子视图;
三、这时候会有两个分支,B和C:
点击的范围再也不B内,所以B分支的pointInside:withEvent:返回NO,对应的hitTest:withEvent:返回nil;
点击的范围在C内,即C的pointInside:withEvent:返回YES;
四、这时候有D和E两个分支:
点击的范围再也不D内,所以D的pointInside:withEvent:返回NO,对应的hitTest:withEvent:返回nil;
点击的范围在E内,即E的pointInside:withEvent:返回YES,因为E没有子视图(也能够理解成对E的子视图进行hit-test时返回了nil),所以,E的hitTest:withEvent:会将E返回,再往回回溯,就是C的hitTest:withEvent:返回E--->>A的hitTest:withEvent:返回E。
至此,本次点击事件的第一响应者就经过响应者链的事件分发逻辑成功的找到了。
不难看出,这个处理流程有点相似二分搜索的思想,这样能以最快的速度,最精确地定位出能响应触摸事件的UIView。
3、说明
一、若是最终hit-test没有找到第一响应者,或者第一响应者没有处理该事件,则该事件会沿着响应者链向上回溯,若是UIWindow实例和UIApplication实例都不能处理该事件,则该事件会被丢弃;
二、hitTest:withEvent:方法将会忽略隐藏(hidden=YES)的视图,禁止用户操做(userInteractionEnabled=YES)的视图,以及alpha级别小于0.01(alpha<0.01)的视图。若是一个子视图的区域超过父视图的bound区域(父视图的clipsToBounds 属性为NO,这样超过父视图bound区域的子视图内容也会显示),那么正常状况下对子视图在父视图以外区域的触摸操做不会被识别,由于父视图的pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。固然,也能够重写pointInside:withEvent:方法来处理这种状况。
三、咱们能够重写hitTest:withEvent:来达到某些特定的目的,下面的连接就是一个有趣的应用举例,固然实际应用中不多用到这些。
http://download.csdn.net/detail/wzzvictory_tjsd/5716299
参考文档:
https://developer.apple.com/library/ios/#documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/event_delivery_responder_chain/event_delivery_responder_chain.html#//apple_ref/doc/uid/TP40009541-CH4-SW1
转自:http://www.cnblogs.com/snake-hand/p/3178070.html
iOS中加载的时候会先执行main函数
根据main函数的参数加载UIApplication->AppDelegate->UIWindow->UIViewController->superView->subViews
AppDelegate ->UIApplication ->UIWindow->UIViewController->UIView->UIButton
关系为:UIApplication.keyWindow.rootViewController.view.subView
事件传递机制:
1.当iOS程序中发生触摸事件后,系统会将事件加入到UIApplication管理的一个任务队列中
2.UIApplication将处于任务队列最前端的事件向下分发。即UIWindow。
3.UIWindow将事件向下分发,即UIView。
4.UIView首先看本身是否能处理事件,触摸点是否在本身身上。若是能,那么继续寻找子视图。
5.遍历子控件,重复以上两步。
6.若是没有找到,那么本身就是事件处理者。若是
7.若是本身不能处理,那么不作任何处理。
其中 UIView不接受事件处理的状况主要有如下三种
1)alpha <0.01
2)userInteractionEnabled = NO
3.hidden = YES
如下来自网络:
响应者链条概念: iOS系统检测到手指触摸(Touch)操做时会将其打包成一个UIEvent对象,并放入当前活动Application的事件队列,单例的UIApplication会从事件队列中取出触摸事件并传递给单例的UIWindow来处理,UIWindow对象首先会使用hitTest:withEvent:方法寻找这次Touch操做初始点所在的视图(View),即须要将触摸事件传递给其处理的视图,这个过程称之为hit-test view。
UIResponder 是全部响应对象的基类,在UIResponder类中定义了处理上述各类事件的接口。咱们熟悉的 UIApplication、 UIViewController、 UIWindow 和全部继承自UIView的UIKit类都直接或间接的继承自UIResponder,因此它们的实例都是能够构成响应者链的响应者对象。
UIWindow实例对象会首先在它的内容视图上调用hitTest:withEvent:,此方法会在其视图层级结构中的每一个视图上调用pointInside:withEvent:(该方法用来判断点击事件发生的位置是否处于当前视图范围内,以肯定用户是否是点击了当前视图),若是pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操做发生的位置,这个视图也就是要找的hit-test view。
hitTest:withEvent:方法的处理流程以下:
首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;
若返回NO,则hitTest:withEvent:返回nil;
若返回YES,则向当前视图的全部子视图(subviews)发送hitTest:withEvent:消息,全部子视图的遍历顺序是从最顶层视图一直到到最底层视图,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者所有子视图遍历完毕;
若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
如全部子视图都返回非,则hitTest:withEvent:方法返回自身(self)。
一次完整的触摸事件的传递响应的过程
UIApplication --> UIWindow --> 递归找到最适合处理事件的控件
控件调用touches方法 --> 判断是否实现touches方法 --> 没有实现默认会将事件传递给上一个响应者 --> 找到上一个响应者
PS:若是直到UIApplication都不响应,那么这个事件就被废弃了。
1.响应者链条:由不少响应者连接在一块儿组合起来的一个链条
响应者:继承自UIResponder的对象称之为响应者对象
2.上一个响应者(默认作法是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理)
如何判断当前响应者的上一个响应者是谁?
1>判断当前是不是控制器的View,若是是,上一个响应者就是控制器
2>若是当前不是控制器的View,上一个响应者就是父控件
3.响应者链条有什么用?
可让一个触摸事件发声的时候让多个响应者同时响应该事件
在子类的实现文件里的touchesBegan:方法里加上以下代码便可
[super touchesBegan:touches withEvent:event]
转自:http://blog.csdn.net/a316212802/article/details/50061317