![dc2c6a244d9fccb849d16b4019135ca3.png](https://i-blog.csdnimg.cn/blog_migrate/dccef04c1e42c5331a8629712a2a5073.jpeg)
概述
当我们点击屏幕之后到应用触发响应,这个过程中发生了什么?如何理解iOS的响应链机制,我们可以通过这个机制实现那些功能?本文将着重讲解iOS响应链机制。
点击屏幕到应用捕获事件
![f772058742543dee8e12b074fa95271e.png](https://i-blog.csdnimg.cn/blog_migrate/f23ebf94f3d34f42aeb395a6cf54adbe.jpeg)
点击屏幕后,经过系统的一系列处理,我们的应用接收到source0
事件,并从事件队列中取出事件对象,开始寻找真正响应事件的视图。
响应者寻找过程分析
寻找相应过程主要涉及到两个方法:
//判断点击的位置是不是在视图内
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;
//返回点击的视图
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;
我们构造了一个简单的视图层级,BlueView/YellowView是两个根节点视图,RedView是他们的父视图。效果如下:
![b0d3436f80ac03fed2946ea5c3a961ff.png](https://i-blog.csdnimg.cn/blog_migrate/339cbb3962515360c5c11b662591fd1f.jpeg)
我们点击一下BlueView,其事件传递效果如下图:
![bc0937bafcc622a2be63e0be68d0b897.png](https://i-blog.csdnimg.cn/blog_migrate/ccfff61b2816d86ef19a5658faa684ec.jpeg)
我们分析一下事件的传递机制。
![88800f182388b47aa707364f4514f5cc.png](https://i-blog.csdnimg.cn/blog_migrate/d99a00965ad8baec16c0a5126748545b.jpeg)
如果到第4步先找的不是YellowView而是BlueView,则不会再去检查YellowView。
找到最终点击的视图之后开始执行响应逻辑。
事件响应过程
我们点击一下BuleView。
如果BuleView没有添加手势事件,则回调用BlueView的touches事件。
输入的日志:
2020-04-25 17:06:48.992130+0800 ResponderDemo[99230:899392] -[BlueView touchesBegan:withEvent:] 2020-04-25 17:06:48.996208+0800 ResponderDemo[99230:899392] -[BlueView touchesEnded:withEvent:]
如果BuleView也没有实现touches事件,那么则会调用父视图的touches事件。
输出日志如下:
2020-04-25 17:12:10.550668+0800 ResponderDemo[99522:904959] -[RedView touchesBegan:withEvent:] 2020-04-25 17:12:10.555622+0800 ResponderDemo[99522:904959] -[RedView touchesEnded:withEvent:]
如何获取响应链
UIResponder *nextResponder = self.buleView.nextResponder;
NSMutableString *pre = [NSMutableString stringWithString:@"--"];
NSLog(@"View3");
while (nextResponder) {
NSLog(@"%@%@", pre, NSStringFromClass([nextResponder class]));
[pre appendString:@"--"];
nextResponder = nextResponder.nextResponder;
}
- 如果有父视图则nextResponder指向父视图
- 如果是控制器根视图则指向控制器
- 控制器如果在导航控制器中则指向导航控制器的相关显示视图最后指向导航控制器
- 如果是根控制器则指向UIWindow
- UIWindow的nexResponder指向UIApplication最后指向AppDelegate。
实践
- Alpha=0、子视图超出父视图的情况、userInteractionEnabled=NO、hidden=YES 视图会被忽略,不会调用hitTest
- 父视图被忽略后其所有子视图也会被忽略
点击穿透
平行视图:重新hitTest,返回想要点击的View
父子视图: 如果子视图是Button 将button的enable改为false。如果是view不要添加手势即可。
限定点击区域
- 判定点是不是在可视坐标内。 pointInside