测试响应者链

这样的层次结构

---A

       ---B

       ---C

              ---D

既A包含B和C,C包含D


测试响应者链_第1张图片

当C的书信clipsTobounds为NO的时候,运行之后显示这样的结果:



测试响应者链_第2张图片


当我们点击D超出C的部分时候,将会是谁响应事件尼?


测试响应者链_第3张图片



对的,这就是打印的结果,是不是非常吃惊!为什么会出现这样的结果尼?道理其实非常简单,当屏幕收到一个触摸事件的时候,就会开始进行命中测试既hit-test,大致的过程如下:

1.  判断UIApplication是否命中触摸事件,是的!就将事件传递给window。

2.  判断window是否命中了事件,是的!就将事件传递给controller。

3.  判断controller是否命中事件,是的!就将事件传递给controller的rootview。

4.  以此类推,判断Aview是否命中事件,是的!就会遍历它所有的子view,分别判断每个子view是否命中事件,发现Bview没有命中事件,就停止对Bview的hit-test。发现Cview也没有命中事件,就停止了对Cview及其子view的hit-test。

5.  这样一来在整个响应者层级中,最顶端(注意:整个响应者链就是一颗多叉树)命中触摸事件的view就是A(因为A的直接子view没有命中事件),因此系统认为A就是最适合处理该事件的响应者,称为第一响应者具备了优先响应事件处理的能力。所以就会出现如上的打印咯!

那么问题来了,怎么样才能让点击D超出C的部分时候D也能响应尼?我们知道,虽然我们点击事件发生在D区域内,但是不在C区域类,而C是D的父亲,故父view不能命中事件,从而导致了子view也不能命中事件。

那么解决的突破口就在于如何让C进行命中测试(hit-test)的时候能够命中事件。OK!只需要在C中重写方法-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event就行啦,具体的代码如下:


测试响应者链_第4张图片

大家应该知道,在进行命中测试的时候会调用hitTest:withEvent:方法,故在此我们重写了该方法。现在就能达到我们想要的效果啦!

示例代码在此:示例代码

你可能感兴趣的:(测试响应者链)