除去高大上的标题,本文主要就是讲当你触碰手机屏幕上任意点的时候,系统是怎样找到那个需要响应该触碰事件的控件,以及该控件对触碰事件的响应情况
首先是 找到应该响应该触碰事件控件的过程:触摸事件首先是被应用的消息循环机制检测到,加入到消息队列,到处理该消息时,由application向下问window,window又去问rootcontroller(这个触摸点在没在你的view范围中),rootcontroller又问自己的view,view又向下问自己的所有子控件,进行筛选,
筛选的规则是:
1.自己是否能接收触摸事件?
2.触摸点是否在自己身上?
3.以上都满足了就从后往前遍历子控件,重复前面的两个步骤
4.如果没有符合条件的子控件,那么就自己最适合处理
这里的“问”默认是通过控件的- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event方法一层一层从外往内掉用;
找到最后找到最适合处理该触摸事件的控件,该控件默认会有对触摸事件的处理:(以下就该是响应者链条的内容了)
根据控件对事件的默认响应情况,大概分三种(肯定不止):
1.button:默认会处理响应该事件,并且不会再调用 [super touchesBegan:touches withEvent:event];向上抛响应,这样该响应链条就断了;
2.uiview: 如果不实现uitouches方法,默认会调用父类(uiresponser)中的touches方法,该方法内部默认会自动把响应交给下一响应者处理;
3.uiimageview:默认是不与用户交互的,所以该控件默认也就不会被选为最佳处理事件的控件,所以该种类不应该算;
如果控件自己实现了touches方法来处理触摸事件,并且响应完又调用了[super touchesBegan:touches withEvent:event];来让下一响应者继续响应,这样一层一层由里向外久构成了响应者链条;
需要说明的是:响应者不都必然是view等控件,也可能是viewController等控制器(UIviewController也继承于UIresponser);
找下一响应者的原则是:
1>如果当前这个view事控制器的view,那么控制器就是上一个响应者(控制器也继承了UIResponser,所有控制器也有touches……方法)
2>如果当前这个view不是控制器的view,那么父控件就是上一个响应者
响应者链的事件传递过程:
1.如果view的控制器存在,就传递给控制器;如果控制器不存在,则将其传递给它的父视图
2.在视图层次结构的最顶级视图,如果也不能处理收到的事件或消息,则其将事件或消息传递给window对象进行处理
3.如果window对象也不处理,则其将事件或消息传递给UIApplication对象
4.如果UIApplication也不能处理该事件或消息,则将其丢弃