看了VV木公子写的史上最详细的iOS之事件的传递和响应机制-原理篇之后,自己写篇文章总结下以便将来回顾。
事件的产生
- 发生触摸事件后,系统会将该事件加入到由UIApplication管理的事件队列中。
- UIApplication会从事件队列中找到最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)。
- 主窗口会在视图层次结构中找到一个最适合的视图来处理触摸事件,这也是整个事件处理过程的第一步。
- 找到最适合的视图控件后,就会调用视图控件的touches方法来做具体的事件处理。
事件的传递
顺序从上到下: UIApplicaton -> Window -> UIViewControleler -> UIView -> subView
指定事件处理视图
- 重写视图的hitTest方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return self; // 指定事件的处理视图,如果是return nil则表示父视图为事件处理对象
}
场景一 : View A拥有两个子视图 View B和View C,B在前,C在后,如果想在触摸B或者C时都让B去处理事件。那么只需要在B和C的父视图A中的hitTest中return self.subviews[0]。
场景二 : View A拥有两个子视图 View B和View C,B在前,C在后,如果想在触摸B或者C时都让C去处理事件。那么不仅可以在B和C的父视图A中的hitTest中return self.subviews[0],也可以在C视图中的hitTest方法里return self。因为父视图在子视图中寻找最合适的事件处理对象是从子视图中最后添加的一个视图从后往前去找:A->C->B。如果在刚才场景一里我们在B里面return self,那么点击C时,B会作为事件处理对象返回吗?不会,因为根据这个寻找时间处理对象的从后往前找的这个机制,会先去找C,如果在父视图没有在hitTest方法里指定子视图的情况下,子视图自身就是事件处理者。
备注:当View被设置为Hidden时或者alpha<=0.01或者userInteractionEnabled=NO,也会响应hitTest方法,如果需要特殊处理一些东西时需要注意下这里。
事件的响应
顺序从下到上: subView -> UIView-> UIViewControleler -> Window -> UIApplicaton
举个例子:
比如有这样一个层级,View A -> View B -> View C,C中如果没有实现touches的一些事件,就拿touchesBegan事件来说好了,如果父视图B中实现了,那么在触摸C的时候则B的touchesBegan事件会响应,一层层往上找。如何一个事件所有的父视图都没实现,直到UIApplicaton都没实现,那么会直接将其丢弃。