iOS开发--响应者链条

简单来说就是 :一级一级的找到响应的视图,如果没有就传给UIWindow实例和UIApplication实例,要是他们也处理不了,就丢弃这次事件...

对于IOS设备用户来说,他们操作设备的方式主要有三种:触摸屏幕、晃动设备、通过遥控设施控制设备。对应的事件类型有以下三种:

1、触屏事件(Touch Event)

2、运动事件(Motion Event)

3、远端控制事件(Remote-Control Event)

响应者链条概念: iOS系统检测到手指触摸(Touch)操作时会将其打包成一个UIEvent对象,并放入当前活动Application的事件队 列,单例的UIApplication会从事件队列中取出触摸事件并传递给单例的UIWindow来处理,UIWindow对象首先会使用 hitTest:withEvent:方法寻找此次Touch操作初始点所在的视图(View),即需要将触摸事件传递给其处理的视图,这个过程称之为 hit-test view。

响应者对象(Responder Object) 指的是 有响应和处理事件能力的对象。 响应者链就是由一系列的响应者对象 构成的一个层次结构。

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)。

假如用户点击了View E,下面结合图二介绍hit-test view的流程:

1、A是UIWindow的根视图,因此,UIWindwo对象会首相对A进行hit-test;

2、显然用户点击的范围是在A的范围内,因此, pointInside:withEvent:返回了YES,这时会继续检查A的子视图;

3、这时候会有两个分支,B和C:

点击的范围不再B内,因此B分支的 pointInside:withEvent:返回NO,对应的hitTest:withEvent:返回nil;

点击的范围在C内,即C的 pointInside:withEvent:返回YES;

4、这时候有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。

***上面找到了事件的第一响应者,接下来就该沿着寻找第一响应者的相反顺序来处理这个事件,如果UIWindow单例和UIApplication都无法处理这一事件,则该事件会被丢弃。***

说明:

1、如果最终 hit-test没有找到第一响应者,或者第一响应者没有处理该事件,则该事件会沿着响应者链向上回溯,如果UIWindow实例和UIApplication实例都不能处理该事件,则该事件会被丢弃;

2、hitTest:withEvent:方法将会忽略隐藏(hidden=YES)的视图,禁止用户操作
(userInteractionEnabled=YES)的视图,以及alpha级别小于0.01(alpha<0.01)的视图。如果一个子视
图的区域超过父视图的bound区域(父视图的clipsToBounds
属性为NO,这样超过父视图bound区域的子视图内容也会显示),那么正常情况下对子视图在父视图之外区域的触摸操作不会被识别,因为父视图的
pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。当然,也可以重写
pointInside:withEvent:方法来处理这种情况。

3、我们可以重写 hitTest:withEvent:来达到某些特定的目的,下面的链接就是一个有趣的应用举例,当然实际应用中很少用到这些。

再深入详细一些:

iOS的事件大致分为三种:触摸事件、加速计事件、远程控制事件

  首先要理解以下几个概念:

  一、响应者对象:

    在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件。我们称之为“响应者对象”。

    UIApplication、UIViewController、UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件。

  二、UIResponder处理事件的主要方法

    触摸事件    

- (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;

    加速计事件

- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;

    远程控制事件

- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

  三、UITouch

    用户同时触摸的手指,每一根就代表一个UITouch对象,它保存着跟手指相关的信息,比如触摸的位置、时间、阶段。

    当手指移动(move)时,系统会更新同一个UITouch对象,使之能够一直保存该手指在的触摸位置。

    当手指离开(end)屏幕时,系统会销毁相应的UITouch对象.

  四、UIEvent

    触摸事件发生,必须会产生一个UIEvent对象,称为事件对象,记录事件产生的时刻和类型。

  五、首先处理事件的响应者

    发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中。

    UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)

    主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步

    找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理

    touchesBegan…

    touchesMoved…

    touchedEnded…

    

    下面是PPT示例,说的很明白。

  

  UIView不接收触摸事件的三种情况

  1.alpha= 0.0 ~ 0.01

  2.hidden属性=YES

  3.userInteractionEnabled=YES

  注意:UIImageView的userInteractionEnabled默认就是NO,因此UIImageView以及它的子控件默认是不能接收触摸事件的

  六、响应者链条

    合适的控件调用touches方法后,会默认地将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理。

  寻找上一个响应者的过程,看起来是寻找首要合适控件的逆过程。

  当前响应者的touches方法中如果调用[super touches],就会对用上一个响应者touches方法,同时可以将UITouch对象和UIEvent对象向上传递。

  这样就能够将一次触摸事件的事件对象和触摸对象的信息传递给多个响应者。

  问题:上一个响应者(nextResponder)是谁?

  判断步骤:
  1>如果当前的view是控制器的view,控制器就是上一个响应者
  2>如果当前的view不是控制器的view,那么父控件就是上一个响应者
  3>如果当前响应者是控制器,那么上一个响应者是UIWindow;如果UIWindow也不处理,就再往上传给UIApplication
  4>如果UIApplication也不处理,那么这条消息就被会废弃

  

  七、触摸事件处理过程

  1.用户触摸后,系统先将事件对象(event)由上往下传递(父控件传给子控件),找到最合适的控件来处理事件(递归查找当前控件的最适合子控件)

  2.调用合适控件的touches相关方法

  3.如果调用了super的touches相关方法,就会将事件顺着响应者链条往上传递,传给上一个响应者

  4.接着就会调用上一个响应者的touches方法

  5.只要当前响应者的touches方法中调用了super的touches方法,还会继续往上递归调用,直到不再调用super的touches方法

时间: 2024-07-31 05:08:59

iOS开发--响应者链条的相关文章

UI开发--响应者链条

一.触摸事件处理的详细过程 用户点击屏幕后产生的一个触摸事件,经过一些列的传递过程后,会找到最合适的视图控件来处理这个事件 找到最合适的视图控件后,就会调用控件的touches方法来作具体的事件处理 touchesBegan… touchesMoved… touchedEnded… 这些touches方法的默认做法是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理 二.响应过程 一次完整的触摸事件的传递响应的过程 UIAppliction --> UIWiondw -->递归找到最

iOS开发 - 响应者链触摸事件

触摸事件 在用户使用app过程中,会产生各种各样的事件 iOS中的事件可以分为3大类型 触摸事件: 加速计事件: 远程控制事件: 响应者对象 在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件.我们称之为"响应者对象" UIApplication.UIViewController.UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件 UIResponder UIResponder内部提供了以下方法来处理事件

iOS开发响应者链触摸事件

触摸事件 在用户使用app过程中,会产生各种各样的事件 iOS中的事件可以分为3大类型 触摸事件: 加速计事件: 远程控制事件: 响应者对象 在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件.我们称之为“响应者对象” UIApplication.UIViewController.UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件 UIResponder UIResponder内部提供了以下方法来处理事件 触摸事件

理解iOS的响应者链条真的很有用

IOS开发——UI进阶篇(十二)事件处理,触摸事件,UITouch,UIEvent,响应者链条,手势识别

触摸事件 在用户使用app过程中,会产生各种各样的事件 一.iOS中的事件可以分为3大类型 触摸事件加速计事件远程控制事件 响应者对象在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件.我们称之为“响应者对象” UIApplication.UIViewController.UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件 二.UIResponder UIResponder内部提供了以下方法来处理事件触摸事件- (v

iOS开发UI篇—响应者链条

iOS开发UI篇—响应者链条 一.触摸事件处理的详细过程 用户点击屏幕后产生的一个触摸事件,经过一些列的传递过程后,会找到最合适的视图控件来处理这个事件 找到最合适的视图控件后,就会调用控件的touches方法来作具体的事件处理 touchesBegan… touchesMoved… touchedEnded… 这些touches方法的默认做法是将事件顺着响应者链条向上传递,将事件交给上一个响应者进行处理 二.响应过程 一次完整的触摸事件的传递响应的过程 UIAppliction --> UIW

IOS开发—事件处理,触摸事件,UITouch,UIEvent,响应者链条,手势识别

触摸事件 在用户使用app过程中,会产生各种各样的事件 一.iOS中的事件可以分为3大类型 触摸事件加速计事件远程控制事件 响应者对象在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件.我们称之为“响应者对象” UIApplication.UIViewController.UIView都继承自UIResponder,因此它们都是响应者对象,都能够接收并处理事件 二.UIResponder UIResponder内部提供了以下方法来处理事件触摸事件- (v

【iOS开发-88】事件传递原理解释哪个控件处理事件以及响应者链条的介绍

一.触摸事件传递原理 (1)大的方向是:从父控件传递给子控件. --父控件会先检查自己是否能接受事件的处理 --然后再看看触摸在不在自己的范围内 --如果在的话,就遍历子控件,看看有没有合适的子控件可以处理 --如果子控件都不适合,那么久父控件自己来处理. 还有个大的原则是,事件一般是从UIApplication >>> UIWindow >>> 各个控件 二.响应者链条 --找到这个控件后,看这个控件有没有实现touches的began.moved和ended事件.

iOS开发中的事件处理(二)-事件传递,响应者链条-

转载请注明出处:http://blog.csdn.net/whjForWork/article/details/44926833 事件处理的事件传递 简介: 发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件 队列中,UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow) UIView不接受触摸事件的三种情况: 不接收用户交互 userInteractionEnabled = NO