响应事件hitTest方法
参考:http://blog.csdn.net/jiajiayouba/article/details/23447145
一.事件的产生
1.发生触摸事件后,系统会将该事件加入到一个由UIApplication管理的事件队列中(为什么是队列而不是栈?因为队列的特定是先进先出,先产生的事件先处理才符合常理,所以把事件添加到队列)。
2.UIApplication会从事件队列中取出最前面的事件,并将事件分发下去以便处理,通常,先发送事件给应用程序的主窗口(keyWindow)。
3.主窗口会在视图层次结构中找到一个最合适的视图来处理触摸事件,这也是整个事件处理过程的第一步。
4.找到合适的视图控件后,就会调用视图控件的touches方法来作具体的事件处理。
二.事件的传递
事件的传递是从上往下的,时间的响应则是从下往上的。
1.触摸事件的传递是从父控件传递到子控件,也就是UIApplication->window->寻找处理事件最合适的view。
2.应用如何找到响应事件的控件?
a.首先判断自己是否能接受触摸事件 -(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
b.触摸点是否在自己身上 -(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
c.从后往前遍历子控件,重复前面的两个步骤(首先查找数组中最后一个元素)
d.如果没有符合条件的子控件,那么就认为自己最合适处理
注意:不参与事件传递的视图:
1.不允许交互:userInteractionEnabled = NO;
2.隐藏:如果把父控件隐藏,那么子控件也会隐藏,隐藏的控件不能接受事件;
3.透明度:如果设置一个控件的透明度为0或者alpha<0.01;
4.视图超出父视图的区域。
三. hitTEST详解
上述过程是系统自动进行的,一般情况下我们不需要干预,当有特殊要求时,可重写hitTest方法,返回需要的视图。
例如:较大的view1上添加较小的view2,实现无论点击view1还是view2,都由view1响应。
我们重写view2的hitTest方法:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *view = [super hitTest:point withEvent:event];
if (view == self)
{
return nil;
}
return [super hitTest:point withEvent:event];
}
实际操作中发现,每次点击事件,hitTest方法会调用两次,查资料发现,两次调用发生在1.消息传递时,2.响应时。分别是入栈出栈操作,父View先入栈,后出栈。(不知这样理解是否正确)