在前面的文章中,我提到了事件传递和响应的U型传递,这里我们通过一个demo模拟来具体查看他的传递和响应顺序,例如点击一个按钮,iOS的后面具体做了些什么呢?
首先我们看下图:
repsonseChain.png
我们点击蓝色的view,系统后面做了些什么操作呢?前面我们说了,我们用手指点击屏幕的时候,硬件接收到了这种touch操作,然后和iOS系统打交道,以source0的形式通知到UIApplication的currentRunLoop(其实也就是mainRunloop),runloop接收到source0事件,将该事件封装成一些对象(这些对象包含事件的一些信息,比如:UITouch、UIEvent)
我们可以通过打断点看到这个调用过程:
source0.png
系统会把该事件加入UIApplication管理的事件队列中去,这个队列是先进先出的,然后UIApplication会从事件队列中去取出最前面的事件,并将事件分发下去以便处理:
以我们这个例子来看,当我点击蓝色view,他的事件传递从最上层的UIAplication逐次向下传递,我们通过下面的代码来模拟:
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
}
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
NSLog(@"查找到了%@",NSStringFromClass([self class]));
// 1.判断下自己能否接收事件
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
// 2.判断下点在不在当前控件上
if ([self pointInside:point withEvent:event] == NO) return nil; // 点不在当前控件
int count = (int)self.subviews.count;
for (int i = count - 1; i >= 0; i--) {
UIView *childView = self.subviews[i];
// 把当前坐标系上的点转换成子控件上的点
CGPoint childP = [self convertPoint:point toView:childView];
UIView *actionView = [childView hitTest:childP withEvent:event];
if (actionView) {
return actionView;
}
}
// 4.如果没有比自己合适的子控件,最合适的view就是自己
return self;
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
return CGRectContainsPoint(self.bounds, point);
}
其实系统会逐次递归调用以上的两个方法,直至找到最合适的view
(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
上面这个方法判断响应事件的point是否包含在自己的frame内部
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
以上这个方法来查找最合适的处理的view,
event distribute desc.png
断点打印如下:
example.png
找到最合适的view(即蓝色的view)以后,这个view会将Touch和Event向上传递:
我们可以通过模拟调用下面这个方法来模拟:
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
}
断点截图如下:
event distribute.png breakPoint stack.png
最终事件回到了最上层的UIApplication,在APPDelegate里重写touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event ,我们会发现断点走到这里来了:
event.png
当然了,iOS系统后面做的一些处理,我们可以在clang命令里面查看C ++源码(这些操作是很复杂的,这里我个人能力有限,请大家自行去研究,菜逼如我是不能给大家分析的),这里简单的模拟下这个过程,意在让读者理解事件传递和响应的顺序和过程,结合前面我写的那片基础点的文章来看, 希望对您理解事件传递和响应有所帮助,写的不对的地方希望读者不吝赐教,如果您觉着对您有帮助,左下角赞我一波啊!🤗
网友评论