**深入浅出的事件路由(view hit test)**

来源:互联网 发布:java 中文分词 对比 编辑:程序博客网 时间:2024/04/26 03:14

ps:大家也许对viewTest(view hit test)比较陌生...敲打敲打

当用户点击屏幕 (事件发生)

1,找到第一个接受事件的控件(control)

2,分发并寻找处理

3,回传直到事件传递给application被废弃.

被称之为事件路由!

响应链(responderChain)只是说的往回传并不告诉你为什么从xx开始分发以及怎么处理这个事件!responderChain只讲传递。 并没有讲,为什么响应链从某个视图开始,为什么不能从别的? 而viewTest机制将给你回答!!!


总结:一个事件发生之后viewTest会选出第一响应者。 因此viewHitTest包括了响应链 。

viewTest将选择出从谁开始

而responderChain将决定怎样传递 ,组合在一起是完整的事件路由。


view 提供了 

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{

//此方法默认被系统实现

}

如果你真的要使用 则应该override(覆盖)那么将会改变路由的起点。

首先,当一个手指 hit 掉在view上, 最下层肯定是window接受到(即第一个视图调用这个方法)

检查,这个点是不是在自己的frame内部 . 如果在,看是否有子视图!如果有,对子视图调用这个方法!

如果没有 则返自己 。按照这个类推  最终找到的是不是点击发生得视图区域的,最上层的视图?  答案是Yeah !!!


给一个场景 __  如果你在一个视图上放一个btn , 而btn的位置却在view的frame的外部 这对于没有经验的程序员来说完全可能!

只要你没给视图设置clipToBounds,你就能看到btn。然而btn是不能接收到事件的!


原因就在于这里

因为当hitTest在btn上调用的时候发现,点击事件并不在它的frame内部。于是,它被忽略了...

事件将由父视图开始,然后往回去传递,正常的将btn放在view内部的时候,btn会最先响应,hitTest会将事件最先递给它!然后,只有btn不响应的时候。

responderChain的规则会将它回传给父视图view


因此 __

hitTest决定了开始的地方
而responderChain决定了如何传递的规则


最后,一个事件如果不在路由中被消耗,那么它最后就会传回到application被废弃回收!

因为,一个控件consume(耗尽)了事件。就像消息,如果有人接受了它就不再存在了。偷笑


当然,你可以改写它得事件处理,让它处理完之后仍然调用super 的处理方法,就传给下一级了。注意,这样得话,你要改写系统所有的类!!!

系统默认,只要一个控件响应了,那么,它将cosume消耗掉这个事件,不会再传递给父类(父视图或者父控制器)!当然,你想要回传,估计你需要重写整个uikit,创造你自己的框架。(什么?几乎不可能的事)。。。

但是,比如在非常特殊的情况下,你必须要回传一级,那么,你可以尝试改写那个视图的touch处理方法!然后在它里面调用nextResponder,那么这个视图就具有了响应事件,并且将事件再传递的能力,但是,注意,有延迟。惊恐惊恐

除非,你把视图的处理方法写到一个异步块里。 不然你的父视图必须等待你处理完了,才能收到。当然你也可以先传递,在于你nextResponder的位置大笑大笑

以上仅为个人见解有任何不对的,不恰当的地方欢迎一起探讨研究!!!


0 0
原创粉丝点击