UIResponder类定义了对象相应和控制事件的接口,他是UIApplication、UIView的超类,这类的实例通常被称为应答对象。
一、Responder对象
在iOS系统中,能够响应并处理事件的对象称之为responder object, UIResponder是所有responder对象的基类,在UIResponder类中定义了处理各种事件,包括触摸事件(Touch Event)、运动事件(Motion Event)和远程控制事件(Remote-Control Events)的编程接口:
触摸事件:
1、当用户触摸到屏幕时调用方法:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
2、当用户触摸到屏幕并移动时调用此方法:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
3、当触摸离开屏幕时调用此方法:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
4、当触摸被取消时调用此方法:
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
运动事件:
1、开始运动时调用方法:
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
2、结束运动时调用方法:
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
3、取消运动时调用方法:
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
远程控制事件:
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;
二、responder chain
在UIResponder中有一个非常重要的概念叫做Responder Chain,responder chain是一系列连接的responder对象,通过responder对象可以将处理事件的责任传递给下一个,更高级的对象,即当前responder对象的nextResponder。在IOS中通常使用hit-testing去找到那个被触摸的视图,这个视图叫hit-test view,当IOS找到hit-test view后就把touchevent交个那个视图来处理。
UIView中有两个方法用来确定hit-test view:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
如上图,这里所有的显示的View都是加载到主window上,点击视图D时看一下hit-testing的工作过程:
1、keyWindow调用pointInside:withEvent:
判断触摸点是否在其范围内,返回Yes,确定该触摸事件发生在view A范围内。
2、ViewA调用pointInside:withEvent:
判断触摸点是否在其范围内,返回Yes,遍历ViewA中的ViewB、ViewC(关于ViewB和ViewC先执行哪个,是根据ViewA添加子控件的先后顺序)。
3、ViewC调用pointInside:withEvent:
判断触摸点是否在其范围内,返回Yes,确定触摸事件发生在了view C中,所以检查 view D,view E。
4、ViewE调用pointInside:withEvent:
判断触摸点是否在其范围内,返回No,ViewE的hitTest:withEvent:
返回nil。
5、ViewD调用pointInside:withEvent:
判断触摸点是否在其范围内,返回Yes,ViewD的hitTest:withEvent:
返回ViewD本身;所以view D成为了hit-test view。
Responder Chain 遵循一个特定的传播路径:如果hit-test view不能够处理该事件则UIKit会将事件传递给下一个Responder。
如上图,
1、初始的界面尝试去处理事件后者消息,把它处理不了则把事件交给它上一层视图处理,因为最开始的界面在它的view controller里的视图层次里不是最上层的。
2、上层视图尝试处理事件,如果他不能处理则将事件交给他的上层视图处理。
3、在view controller中最上层的视图尝试处理,它也不能处理则交给它的view controller来处理。
4、如果view controller也无法处理则交给window来处理。
5、window无法处理交给app object来处理。
6、app object也无法处理则将该事件丢弃掉。
管理响应链:
UIResponder提供了几个方法来管理响应链,包括让响应对象成为第一响应者、放弃第一响应者、检测是否是第一响应者以及传递事件到下一响应者的方法。
1、负责传递事件的方法是nextResponder
- (UIResponder *)nextResponder;
2、判定一个响应对象是否是第一响应者
- (BOOL)isFirstResponder;
3、将一个响应对象作为第一响应者
- (BOOL)becomeFirstResponder;
4、判定一个响应对象成为第一响应者的一个前提是它可以成为第一响应者
- (BOOL)canBecomeFirstResponder;
5、与上面两个方法相对应的是响应者放弃第一响应者的方法
- (BOOL)resignFirstResponder;
- (BOOL)canResignFirstResponder;