响应链
image.png- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window.rootViewController = [[ViewController alloc] init];
[self.window makeKeyAndVisible];
return YES;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIView *view = [[UIView alloc] init];
[self.view addSubview:view];
UILabel *label = [[UILabel alloc] init];
[view addSubview:label];
[self logOutResponderChain:label];
}
- (void)logOutResponderChain:(UIResponder *)responder {
UIResponder *nextResponder = responder.nextResponder;
NSLog(@"%@ -> ", NSStringFromClass([responder class]));
while (nextResponder) {
NSLog(@"%@ -> ", NSStringFromClass([nextResponder class]));
nextResponder = nextResponder.nextResponder;
}
NSLog(@"*");
}
// - 打印结果 : UILabel -> UIView -> UIView -> ViewController -> UIDropShadowView -> UITransitionView -> UIWindow -> UIWindowScene -> UIApplication -> AppDelegate -> *
- 能响应事件的 必须是UIResponser的子类;
- 响应链是 子视图-> 父视图的.
传递链
image.png- 首先判断主窗口(keyWindow)自己是否能接受触摸事件
- 判断触摸点是否在自己身上
- 子控件数组中从后往前遍历子控件,重复前面的两个步骤(所谓从后往前遍历子控件,就是首先查找子控件数组中最后一个元素(后添加到view上的子view - > 先添加到view上的子view),然后执行1、2步骤)
- view,比如叫做fitView,那么会把这个事件交给这个fitView,再遍历这个fitView的子控件,直至没有更合适的view为止。
- 如果没有符合条件的子控件,那么就认为自己最合适处理这个事件,也就是自己是最合适的view。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
NSLog(@"AView --- hitTest");
UIView * view = [super hitTest:point withEvent:event];
NSLog(@"AView --- hitTest --- return %@", view.class);
return view;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
NSLog(@"AView --- pointInside");
return [super pointInside:point withEvent:event];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"AView --- touchesBegan");
}
// - [vc.view addSubView: AView]; [AView addSubView: BView]; [BView addSubView: CView];
// - 触摸CView
AView --- hitTest
AView --- pointInside --- Yes
BView --- hitTest
BView --- pointInside --- Yes
CView --- hitTest
CView --- pointInside --- Yes
CView --- hitTest --- return CView
BView --- hitTest --- return CView
AView --- hitTest --- return CView
CView --- touchesBegan
// - 触摸BView但是不触摸CView
AView --- hitTest
AView --- pointInside --- Yes
BView --- hitTest
BView --- pointInside --- Yes
CView --- hitTest
CView --- pointInside --- No
CView --- hitTest --- return (null)
BView --- hitTest --- return BView
AView --- hitTest --- return BView
BView --- touchesBegan
总结
用户产生触摸事件 -> 事件进入UIApplication事件队列 -> UIApplication分发事件给keyWindow -> [UIWindow hitTest:withEvent:] -> [UIView hitTest:withEvent:] -> … -> [UIView hitTest:withEvent:] -> 返回最合适的view给keyWindow -> [UIWindow _sendTouchesForEvent:] -> [UIView touchesBegan:withEvent:]。
网友评论