响应者链
2016-09-29 本文已影响0人
noprkl
什么是响应者链
在iOS的事件传递过程中需要通过多个响应者来寻找最合适的事件接收者,把这个过程中的响应者串联起来就是响应者链。
事件的产生和传递过程
当系统检测到触摸事件
event
发生的时候,将event
放入当前活动的UIApplication
事件队列中,UIApplication
会从队列中取出event
传递给主窗口UIWindow(keyWindow)
,keyWindow
会通过递归找到合适的View
,调用touches
;
触摸事件
event
——>UIApplication
队列——>UIWindow
对列接收——>keyWindow
递归找到View
——>View
调用合适的touches
——>处理事件
递归寻找响应者 (hitTest:withEvent:和pointInside:withEvent:)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
NSLog(@"%@-hit-%@", NSStringFromClass(self.class), event);
// 1.判断能否接受点击事件
if (!self.userInteractionEnabled || self.alpha == 0.0 || self.hidden) {
return nil;
}
// 2.判断点是否点击在当前视图上
if (![self pointInside:point withEvent:event]) {
return nil;
}
// 反向遍历子视图
__block UIView *fitView = nil;
[self.subviews.reverseObjectEnumerator.allObjects enumerateObjectsUsingBlock:^(UIView *childView, NSUInteger idx, BOOL * _Nonnull stop) {
// 把当前坐标系上的点转换成子控件上的点
CGPoint chidlPoint = [self convertPoint:point toView:childView];
// 判断这个点上是否在子视图上,找到第一个响应视图
fitView = [childView hitTest:chidlPoint withEvent:event];
if (fitView) {
*stop = YES;
}
}];
if (fitView) {
return fitView;
}
return self;
}
寻找合适的响应者
如果响应者处理不了
touches
事件,会将事件上移,该类的上一级如果是UIView
,子视图处理事件,处理不了,寻找它的父视图
该类的上一级如果是UIViewController
,则是由它所属的控制器处理
事件上移到最顶层如果处理不了,把事件传递给UIWindow
,UIWindow
处理不了给UIApplication
,UIApplication
默认不响应,这个touches
就会被吃掉
寻找当前view的UIViewController
思路:
根据响应者链寻找,找到相应当前view事件的控制器
1.给当前控制器添加一个导航条 ‘nav’ 是window的rootViewController
UIViewController *vc = ((AppDelegate *)[UIApplication sharedApplication].delegate).nav.visibleViewController;
2.通过遍历当前view的响应者链 找到
View
所属的控制器
- (UIViewController *)viewController:(UIView *)view
for (UIView *next = view; next; next = next.superview) {
UIResponder *responder = [next nextResponder];
if ([responder isKindOfClass:[UIViewController class]]) {
return (UIViewController *)responder;
}
}
return nil;
}