事件传递:响应者链条

事件传递:响应者链条

当用户生成(user-generated)事件发生,UIKit创建一个事件对象,来包含用户生成
事件的信息,然后把该事件添加到应用程序活动事件队列。对于触摸事件,该对象是包含在
UIEvent对象的touches的组合包。对于运动事件,该对象取决于使用的框架以感兴趣的运行
事件类型。
一个事件按照特定的路径进行传递,知道找到可以处理他的对象。首先UIApplication
单例对象从事件队列头部取出一个事件进行派发执行,通常情况,UIApplication首先发送事
件给应用的主窗口对象(app’s key window object),主窗口对象把事件传递给能够处理他
的初始化对象,初始化对象依赖于事件的类型。
1、触摸事件
对于触摸事件,窗口对象首先尝试把事件传递给触摸发送的那个view。这个view被称作
hit-test view。寻找hit-test view 的过程叫做 hit-testing。

2、运动事件和远程控制事件
通过这些事件,窗口对象发送 shaking-motion 或者 远程控制事件给第一响应者。

这些事件的路径最终是要找到一个可以处理事件、响应事件的对象。因此UIKit首先发送
事件给最适合处理这个事件的对象。对于触摸事件,这个对象是hit-test view,对于其他的事
件,这个对象是第一响应者。


Hit-Testing 返回触摸发生的view
iOS 采用 Hit-Testing 过程来寻找触摸发生的view。Hit-Testing 包含检查是否发生在任何
相关的view对象的范围之内,如果在他会递归检查这个view 的所有的subViews。在视图框架最
底层的 触摸点击事件发生的那个view就是 hit-test view。在iOS找到hit-test view后,会把事件
传递给他进行处理。

举例说明,假定用户点击 view E 在 图2-1,iOS寻找hit-test view按照下面的顺序检查subViews
1、触摸点在view A的范围中,检查A的subViews B 和 C。
2、触摸点不在view B的范围,而在View C,所以继续检查C的subView D 和 E。
3、触摸点不在view D的范围内,而在View E。

view E 就是 hit-test View,他处于 层视图的lowest。
        

 方法 hitTest:withEvent: 通过传入的CGPoint和UIEvent  返回hit-test view。hitTest:withEvent:
在内部调用 pointInside:withEvent:。如果hitTest:withEvent:的传入参数CGPoint在当前view的
内部,pointInside:withEvent:返回YES。然后这个方法在view的所有返回YES的子view递归调用
hitTest:withEvent:
假如传入hitTest:withEvent:的点没有在当前view的范围之内,第一个调用pointInsid:withEvent:
的方法返回NO,那么这个点被忽略,hitTest:withEvent:返回nil。如果一个subview返回NO,那么
整个继承的分支会被忽略,因为触摸点没有发生在subView上,那么subView的subViews也不会发生。

那这意味如果subView的属性clipsToBounds设置NO,处于这个subview的在他们的父视图之外
的任何点是不能接受触摸事件,因为触摸点必须在父视图和子视图的范围之内,,这就会发生。
这些点就是clipsToBounds设置NO的时候,子视图在父视图之外的所有点。

注:触摸物体与它的hit-test视图其生命周期相关联,即使触摸的观点外后移。

Hit-Test view是处理触摸事件的第一选择,如果Hit-Test view不能处理这个事件,在view的响应
者链中寻找,直到系统找到可以处理他的对象。

响应者链条由响应对象组成

许多类型的事件依赖响应者链条进行传递。响应链是一系列相关的响应器组成。他开始于第一响
应者,结束于application 对象。如果第一响应者无法处理事件,那么会根据响应者链条传递给下一个
响应者。
响应者是一个可以响应和处理事件的对象。UIResponder类是所有响应对象的基类,他定义的程序
接口不单单包含事件处理,也包括通用的响应行为。UIApplication、UIViewController、UIView类实例都是
响应者,这意味着所有的view和大部分关键的Controller对象都是响应者。需要注意的是和谐动画层不是
响应者。

第一响应者被设计第一个接收事件,典型的,第一响应者是一个view对象。一个对象成为第一响应者
需要做以下两点:
1、覆盖canBecomeFirstResponder 方法返回YES
2、接收 becomeFirstResponder 消息。如果必须,一个对象发送给自己这种消息。

注意:确保你的app程序在一个对象成为第一响应者之前确立了其对象图。例如:通常在viewDidApper方法
         中重新 becomeFIrstResponder方法。假如你shit分配第一响应者咋viewWillAppear,你的对象图还没
         有确定,所以 becomeFirstResponder 方法返回 NO。


事件不是第一响应者依赖的唯一的对象,响应连应用于下列所有情况:

1、触摸事件。
假如 Hit-test view不能处理触摸事件,从hit-test View 开始事件被在响应者链中传递
2、运动事件
为了和UIKit处理 shake-motion事件,第一响应者必须实现UIResponder类的中的
 motionBeagan:withEvent 和 motionEnded:withEvent:

3、远程控制事件
为了处理远程控制事件,第一第一响应者必须实现UIResponder类的中的
remoteControlReciviedWithEvent

4、获得消息(Action messages)
当用户进行一个操作,比如button或者switch,他们的target方法是nil,那么消息将通过
响应链的起始控制视图进行传递

5、编辑菜单中的消息(Eding-menu message)
当用户点击编辑菜单中的命令,iOS使用响应者链来找到实现了必要方法(比如cut:、
copy:、path:)的对象。

6、文本编辑(Text Editing)
当用户点击text field 或者 text view,那么这个view就自动成为第一响应者。默认情况下
虚拟键盘出现,text field 或者 text view 成为编辑的焦点。你可以显示一个自定义输入view取
                代键盘,你也可以添加一个自定义输入view给任何响应对象。

UIKit 自动设置 text field 或者 text view 用户点击成为第一响应者;apps 必须显式通过
becomeFirstResponder设置所有其他第一响应者对象


响应者链按照特定的分派路径

假如初始化对象 —— hit-test view 或者第一响应者对象 ——— 不能处理事件,UIKit
会把事件传递给响应链中的下一个响应者。每一个响应者决定是否处理事件或者通过调用
nextResponder方法来把事件传递给下一个响应者。持续这个过程直到找到一个响应者对象 
或者没有更多的响应者.
   当iOS发现事件并把他传递给初始化对象时,响应者链开始执行,这是一个view典型的
开始。initial view 具有处理事件的第一机会,图2-2展示两个不同的事件派发路径在两种app
配置。一个应用程序的事件传递路径取决于他的具体结构,但是所有的事件传递路径遵循相同
的试探方法。


对应左边的App,事件遵循下面的路径:
1、initial尝试处理事件或者消息,假如他不能处理这个事件,就把事件传递给他的父视图,
     因为initial view 不是视图层次图的最顶层。

2、父视图尝试处理事件,如果父视图不能处理事件,父视图继续事件给传递他的父视图,因
     为父视图仍然没有在视图层次的最顶端。

3、 在视图控制器的视图层次的最顶层view尝试处理事件,假如最顶层的view不能处理事件,
      事件被传递给他的视图控制器

4、视图控制器尝试处理事件,如果他不能处理把事件传递给 window

5、如果 window 对象不能处理事件,传递事件给 单例app对象

6、如果app 对象不能处理事件,事件被丢弃

右侧的 app 遵循稍微不同的路径,但是所有事件的传递路径按照下面的试探过程
1、一个view传递事件up 他的视图控制器的 view 试探直到到达顶层的view

2、顶层的view 传递事件给他的控制器

3、view 控制器传递事件给他的 父类view

 重复1-3 直到事件到达根控制器

4、根控制器传递事件给 window对象

5、window对象传递事件给 app 对象

重要提示:如果你实现一个自定义view来处理远程控制事件,action messages, shake-motion 
with UIKit,或者编辑菜单消息,不要将事件或消息转发给nextResponder直接
转发给它发送响应链。相反,调用父类执行现有的事件处理方法,让UIKit的处理
响应链的遍历为您服务。

--------------------------------------------------------------------------------------------------------------







































--------------------------------------------------------------------------------------------------------------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值