事件传递:响应者链
当你设计你的app 时候,经常动态地响应事件对不对。比如,屏幕上的许多对象都会触发一个触摸的事件,你必须决定让谁来响应这个时间并且要明白这个对象怎么接收到事件。
当一个用户产生的事件发生时,UIKit 创建了包含处理该事件所需要的信息。然后这个事件对象进入 一个app对应的事件队列。 对于触摸事件来说,该对象是一系UItouches对象的打包。对于手势来说,该对象则是手势的类型。
一个事件是经由特定的路径到达能处理的对象的。一开始是UIApplication,其次是key window, 其次到initial object.
对于触摸事件来说, window 会传到 发生触摸的view,被称之为hit-test view。
此过程叫 hit-testing。
对于手势和远程控制,这个第一响应被发到 first responder.
最终响应者链要找到处理事件的对象。规则如下。
1 Hit_testing (检测的过程实际上是自上而下的)
1 此触摸被检测抖到在A的边界内,所以继续检测B和C。
2 同样的道理,继续检测C的子类D和E。
3 最后排除了D,检测E。
View E已经是最低层的View,所以它使hit-Test找到的对象。
hitTest:withEvent: 参数为CGpoint 和 UiEvent。
hitTest:withEvent: 的实现都是以pointInside:withEvent:为检验的,先检验自己然后再检验subview,所以触摸点是必须在superview然后同时在view才会被传下来,如果都没有在superview检测到是不会被传下来的。这种情况适用于cliptobounds的情况。
然后就是nextresponder了。响应者链的组成部分是Responder, Responder的
nextResponder方法决定了传递的规则,然后苹果公布的规则是这样子的
参考的路径
1 initial view-》 view-》view的Controller -》window -》 application
2 initial view-view -》view的controller -》view -》viewController -》window -》application
按照文档的推论
1 任何一个view的-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
return NO;
}都会导致其的sperview成为 hittestview
2/**
* 发送一个路由器消息, 对eventName感兴趣的 UIResponsder 可以对消息进行处理
*
* @param eventName 发生的事件名称
* @param userInfo 传递消息时, 携带的数据, 数据传递过程中, 会有新的数据添加
*
*/
- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo;
@implementation UIResponder (Router)
- (void)routerEventWithName:(NSString *)eventName userInfo:(NSDictionary *)userInfo
{
[[self nextResponder] routerEventWithName:eventName userInfo:userInfo];
}
@end
3 成为一个responder类,这在成为菜单类弹出的响应者时特别有用 https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/AddingCustomEditMenuItems/AddingCustomEditMenuItems.html#//apple_ref/doc/uid/TP40009542-CH13