First Steps
Tips1:Understanding Event Handling, Responders, and the Responder Chain
- 概述:Apps 接受和响应事件均使用 UIResponder 对象,它的子类包括 UIView, UIViewController, UIApplication 。一个 responder 类接受原生的事件数据然后将它传递给其他的 responder 对象。当你的 app 接受到了一个事件, UIKit 将会自动的将这个事件发送给最可能接受的对象 ——
first responder。它没有能 handle 的事件将会通过响应链传递给一个又一个的 responder,这些都是在你的 app 中动态配置的。在你的 app 中,不止有一条响应链。 UIKit 默认定义了对象如何在 responder 之间传递的规则,不过你可以通过自己修改某些方法的方式来完成对这一特性的修改,定制自己的传递规则。当界面上有一个 textfield 两个背景 view 时,首先如果这个 textfield 无法 handle 某一事件,它将会被传递给它的父视图上去。在 rootView 上,它将会把这个事件传递给它自己的 viewController, 然后才会继续传递给 UIWindow。如果 UIWindow 还无法 handle 这个事件,它将会被传递给 UIApplication 对象,当这个对象时 UIResponder 的实例并且也不在响应链中,这个事件也有可能会被传递给 UIApplicationDelegate 。responderChain.png
-
为一个事件选择第一响应者:对于每一种事件来说, UIKit 都会先选择某一种 firstResponder 然后先把事件传递给它。
-
Touch event:它的第一响应者是当 touch 动作发生时所在的 view -
Press event:它的第一响应者是 -
Shake-motion event/RemoteControl event/EdtingMenu event:它的第一响应者是你指定的 firstResponder - 需要注意的是:motion 事件和螺旋器,加速仪等有关系,它并不 follow 响应链。
- 控件类直接与他们的 target object 使用 action messages 发送消息。也就是说,当一个用户与一个 UIControl 类进行交互时,它将把这个动作消息发送给它的目标对象。实际上 UIControl 类也能享受到响应链的优点,因为当一个控件并没有设置它的 target action 时, UIKit 会开始沿着当前 UIControl 对象的响应链寻找一个可能接受这个 action method 的对象。例如: UIKit 的 edting menu 就是用这个特性去寻找可以实现 cut,copy 等方法的对象。
- 如果一个 view 添加了一个手势,这个手势会首先接受 touch 和 press 事件,只有当所有的手势都无法接受这个事件后,这个事件才会被传递给这个 view 去 handle。
-
-
决定哪一个响应者包含一个 Touch 事件:UIKit 使用
hitTest:withEvent:方法去判断当前 touch 事件是在哪里发生的。 UIKit 会在继承链中比较这个 touch location 和 view 对象的 bounds。hitTest:withEvent:方法会穿越 UIView 的 view 继承链,然后寻找最底下包含这个 touch 事件的子视图,这个 view 就会成为这个 touch 事件的 firstResponder- 如果一个 touch 事件的位置在 view 的 bounds 外,
hitTest:withEvent:方法就会忽略这个 view 和它的所有子视图。当一个 view 的 clipToBounds 属性设置为 NO 时,表示并不裁剪这个 view 的子视图。那么如果这个 view 的 subViews 如果在这个 view 的 bounds 外,即使这个 subView 接收到了 touch 事件,也不会去处理的。也就是说,hitTest:withEvent:方法已经自动把这个 subView 过滤掉了。 - 当第一次发生了这个 touch 事件时, UIKit 会创建 UITouch 对象,然后只有等到这个 touch 事件结束时才会释放这个 touch 对象。当 touch 的 location 或者其他的参数改变时, UIKit 会自动的更新 UITouch 对象的信息。唯一不会改变的属性为这个 touch 事件的 containing view。即使这个 touch 事件的位置有可能会移出它一开始的 origin containing view 的范围,这个 touch view 的属性也不会改变。
- 如果一个 touch 事件的位置在 view 的 bounds 外,
-
改变响应链:你可以通过重写
nextResponder属性来改变响应链。当你这样做时, nextResponder 对象就是你返回的对象。许多 UIKit 类已经改写了这个属性- UIView 对象:如果这个 view 是一个 viewController 的 rootView,那么它的 nextResponder 就是这个 viewController,否则,这个 view 的 nextResponder 是它的 superView
- UIViewController 对象:如果这个 viewController 是被另外一个 viewController present 过来的,那么他的 nextResponder 就是 present 它的那个 viewController
- UIWindow 对象:它的 nextResponder为 UIApplication 对象
- UIApplication 对象:只有当一个 app delegate 对象是 UIResponder,并且它不是一个 view,viewController或者 app 自身时,UIApplication对象的 nextResponder 才为 app delegate 对象
Tips2:class UIResponder
- 概述:responder 对象是 UIResponder 类的实例,他们在一个 UIKit app 中组成了事件处理的支柱。很多 key object 也是 responder 对象。包括 UIApplication 对象, UIViewCOntroller 对象,和 UIView 对象(包括 UIWindow 对象)。当事件发生时,UIKit 将这些事件分发给你的 app 内的 responder 对象来处理。
- 事件有许多种类,包括 touch 事件,motion 事件,remote-control 事件,和 press 事件。想要去 handle 这些事件对象,我们必须重写相应的方法,比如说我们如果想 handle 一个 touch 事件,我们可以实现
touchesBegan:withEvent:,touchesMoved:withEvent:,touchesEnded:withEvent:, 和touchesCancelled:withEvent:方法。在 touch 的条件下,responder 对象使用这些 UIKit 提供的事件信息去追踪 touches 的改变,并且也可以更新 app 的界面。 - Responder 对象处理 UIEvent 对象,也可以接受其他通过 inputView 输入的普通 input,系统的 keyboard 是一个最明显的 inputView。当 user 点击 textfield 和 textView 对象时,那个 view 就会成为 firstResponder 然后被展示在屏幕上。同理,你也可以创建自己的 custom input view 然后将它展示在屏幕上。如果想将一个普通的 input view 关联为一个 responder ,可以将那个 view 通过设置为 inputView 属性分配给 responder。
Tips3:class UIEvent
- 概述:Apps 可以接受很多类型的事件,包括 touch 事件, motion 事件,和 press 事件等。Touch 事件是最常见的事件,它会传递给 touch 最初发生的 view。 RemoteControl 事件使 responder 对象能够接收一个从外部控制的事件,例如耳机,所以它可以控制音频和视频。
- 一个 touch event 对象包括很多 touches (即有很多手指同时 touch)所以和 event 有一定的关系。一个 touch event 对象可能包括一个或多个 touches ,每个 touch 都是一个 UITouch 对象。当 touch event 发生时,系统自动的将它路由到适当的 responder,然后调用适当的方法。例如
touchesBegan:withEvent:。然后 responder 接着使用这些 touches 去定义可能发生的动作 - 在一个多点触控过程做,UIKit 会复用同样的 UIEvent 对象,所以你永远都不应该去保存一个 event 对象/一个对象从 event 返回。如果你需要保存一个 responder 以外的数据,你应该去保存数据,将 UITouch / UIEvent 对象的数据保存到本地数据结构中。
总结:
- 此为 iOS 开发中的 UIKit 响应链部分的第一部分,翻译 + 个人理解自苹果官方文档 Touches, Presses, and Gestures,如有理解错误望海涵和指正。
