当对某一个View或者VC进行一次操作时候,其实际的传递和响应过程如下:
-
传递链
a. 从UIWindows开始向下传递,每次都对当前响应者调用hitTest函数,当hitTest函数返回nil的时候则会继续向subView层调用,否则传递链结束,传递到hitTest返回的控件;
b. hitTest函数内部会调用pointInside函数,判断当前点击的point是否在当前正在判断的subView内,如果不在(或者该subView的alpha过小,被隐藏等等)则直接返回nil,否则继续调用该控件的所有subView的hitTest,直至没有subView;
c. 此时即可确定当前传递到的控件是哪一个,即由该控件来对该操作进行响应。
-
响应链
a. 设传递链获取到的控件为A,那么则由A开始向A的父对象进行响应,如果当前对象可以响应这个操作(即实现了touchesBegin等四个函数或者motionBegan等三个函数或者远程控制器函数),则响应链结束,并由该对象响应这个操作,否则递归判断当前对象的父对象是否可以响应该操作,此递归一直调用到UIApplicationDelegate为止,如果UIApplicationDelegate也不能响应,则丢弃该操作;
b. 如果传递链获取到的控件A为UIControl对象,则会跳过路上的父节点直接交由UIApplication进行响应。
-
手势操作链
a. 确定了由哪一个对象响应该操作之后,设该对象为B
b. 首先会调用touchesBegin方法,然后判断此时的操作是否满足B上定义的自定义手势(如果没有自定义手势则视为不满足),如果满足则响应该手势,并调用touchesCancel,否则调用touchhesEnded结束touch;
c. 在响应手势操作前,如果当前对象遵循了UIGestureRecognizerDelegate,则调用如下函数:
1 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch; |
判断是否需要响应该手势,如果不需要返回NO(可以通过判断touch.view来判断当前点击的对象),需要则返回YES。
- 要在touchesBegin等函数中判断当前是几根指头的操作,需要调用event.allTouches.count并对event.allTouches内的所有UITouch对象调用tapCount属性判断当前UITouch对象点击了几次。此外还可以用timeStamp获得当前操作的时间戳(系统开始时间到操作时间)