iOS系统检测到手指触摸(Touch)操做时会将其放入当前活动Application的事件队列,UIApplication会 从事件队列中取出触摸事件并传递给key window(当前接收用户事件的窗口)处理,window对象首先会使用hitTest:withEvent:方法寻找这次Touch操做初始点所在的 视图(View),即须要将触摸事件传递给其处理的视图,称之为hit-test view。html
window对象会在首先在view hierarchy的顶级view上调用hitTest:withEvent:,此方法会在视图层级结构中的每一个视图上调用pointInside:withEvent:,若是pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操做发生的位置,这个视图也就是hit-test view。ios
hitTest:withEvent:方法的处理流程以下:数组
hitTest:withEvent:方法忽略隐藏(hidden=YES)的视图,禁止用户操做(userInteractionEnabled=YES)的视图,以及alpha级别小于0.01(alpha<0.01)的视图。若是一个子视图的区域超过父视图的bound区域(父视图的clipsToBounds 属 性为NO,这样超过父视图bound区域的子视图内容也会显示),那么正常状况下对子视图在父视图以外区域的触摸操做不会被识别,由于父视图的 pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。固然,也能够重写 pointInside:withEvent:方法来处理这种状况。app
对于每一个触摸操做都会有一个UITouch对 象,UITouch对象用来表示一个触摸操做,即一个手指在屏幕上按下、移动、离开的整个过程。UITouch对象在触摸操做的过程当中在不断变化,因此在 使用UITouch对象时,不能直接retain,而须要使用其余手段存储UITouch的内部信息。UITouch对象有一个view属性,表示此触摸操做初始发生所在的视图,即上面检测到的hit-test view,此属性在UITouch的生命周期再也不改变,即便触摸操做后续移动到其余视图之上。ide
若是父视图须要对对哪一个子视图能够响应触摸事件作特殊控制,则能够重写hitTest:withEvent:或pointInside:withEvent:方法。spa
这里有几个例子:code
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *result = [super hitTest:point withEvent:event]; CGPoint buttonPoint = [underButton convertPoint:point fromView:self]; if ([underButton pointInside:buttonPoint withEvent:event]) { return underButton; } return result; }
这样若是触摸点在button的范围内,返回hittestView为button,从button按钮能够响应点击事件。htm
网上的一个案例: 对象
convertPoint:toView:blog
转换一个点从接收者坐标系到给定的视图坐标系
- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view
参数
point
一个在调用者坐标系中的点
view
一个包含了须要被转换的点的视图。若是视图是nil,那么这个方法将会转换成基于窗口的坐标。不然视图和接收者都要属于同一个UIWindow对象。
返回值
基于视图的坐标系转换过的点