ios 中事件的处理接口或者说协议是由UIResponder 定义的。
最主要的事件就是touch事件,touch事件是 UIAapplacation 对象 runloop 检测到并封装的。UIApplaction 对象封装好后将事件传递给UIWindeow对象。touch 事件的处理分为两步,第一个步是找到 该touch 所对应的 view,即touch 是那个在那个view上的;第二是步是找到处理该该事件的对象。
第一步的实现,直接调用 UIWindow的
none
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
方法,该方法 会返回 以调用者为 根的view 树 中touch 事件 所对应的view。该方法的实现是调用所有子view的
none
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
然后返回 yes 的 子 view 调用
none
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
这样递归调用直到不存在 叶子 view ,然后返回该View。需要注意的这个递归调用每次传递的 point 值实景过转换的。实在 相应view坐标系下的position。
需要说明的是 view 的UIinterfaceEnable 和 存在 gesture recognize 的 会影像这个过程的进行。 UIinterfaceEnable 为no 的 ,gesture recognize 的 canceltouchinview 为yes 的 则该 过程不会 进行下去。UIinterfaceEnable 为no 的 则 super view 不会 hittest 这样的子view。gesture recognize 的 canceltouchinview 为yes 的 view 不会 hittest 子view。
第二步是找到处理该事件的对象。从第一步找到的View开始 沿着 reponder chain 将 事件传递下去。需要注意的是responder chain 中某一个对象可以 不将 事件 继续往下传,那么 responder chain 下面的对象就不会处理该对象。常见的 chain 是 view –> viewController –>super view –> superview controller —> super super view —> supersuperview controller 最后到rootcontroller 然后到window。需要注意的是 viewcontroller的下一个 responder 是 superview。ios 如果view congroller 的使用不是 按照tabbar navigationbar viewcongroller的方法来使用,就可能产生 responder chain 不对的情况。 (直接将view congroller 的 view addsubiew 到其他view 上)
从上面我们可以看出 一个事件 可以让多个对象同时 知道 并进行处理。这个chain 的实现 的接口就是
none
- (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;
该四个方法的默认实现是调用 nextresponder 的该四个方法。也就是说如果不复写这几个方法,则事件会最终传递到 window,window 的处理一般是直接丢弃。
下面来说说UIGestureRecognizer:
UIGestureRecognizer 对象是添加到 view 对象上面的,当view 收到 hittest 时候,该GestureRecognizer 会被通知到。GestureRecognizer 也是 有并封装了 上面四种方法,然后根据 touch 事件的时间 位置 特征 来 进行 特定的动作。ios系统中提供了 一些UIGestureRecognizer 的子类,这些子类就是处理特定的 touch 序列的。
UIGestureRecognizer 提供了一些代理来 方便的封装了 对上面四种 方法的实现进行 配置。如下面的方法 定义了 是否 根据情况 将 touch 事件 加入到事件序列中,生成响应的动作。
none
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
除了touch 事件的 其他事件的 处理 需要引入 第一响应者,这些事件包括
none
- Motion events—via calls to the UIResponder motion-handling methods described in “Shaking-Motion Events”
- Remote-control events—via calls to the UIResponder method remoteControlReceivedWithEvent:
- Action messages—sent when the user manipulates a control (such as a button or slider) and no target is specified for the action message
- Editing-menu messages—sent when users tap the commands of the editing menu (described in “Displaying and Managing the Edit Menu”)
程序中只有一个第一响应者。第一响应者 相关的 函数是
none
- (BOOL)canBecomeFirstResponder; // default is NO
- (BOOL)becomeFirstResponder;
- (BOOL)canResignFirstResponder; // default is YES
- (BOOL)resignFirstResponder;
- (BOOL)isFirstResponder;
对象通过 – (BOOL)becomeFirstResponder; 来向程序 将自己(或者别的对象)注册成第一响应者。被注册者通过- (BOOL)canBecomeFirstResponder;方法来表示自己是不是原因 成为第一响应者。 需要第一响应者的事件到来后,事件会交给第一响应者,然后第一响应者沿着 responder chain 将事件传递下去。motion 事件的 responder chain 是由
none
方法来实现的,该方法 同 touch responder chain 的方法 实现相同,如果没有对象处理,则传递给 UIApplication 对象,然后丢弃。
(转自:http://dcm19872007.blog.163.com/blog/static/865193742013018112558478/)