防止子视图控制器上的未处理触摸事件传递到容器视图

时间:2017-10-03 08:06:27

标签: ios uiviewcontroller uigesturerecognizer uitouch uiresponder

我有一个容器视图控制器管理自己的全屏内容视图,附带了几个手势识别器。子视图控制器可以覆盖在屏幕的一部分上;它的根视图是一个提供不透明背景颜色的UIView,它由UIScrollView覆盖,而UIScrollView又包含堆栈视图的复杂视图层次结构等。

滚动孩子可以正常工作,以及任何用户与其子视图的互动。我遇到的问题是,滚动视图本身上的任何点击或其他非滚动手势(即不在其任何子视图中)都会通过其后面的空UIView掉落,并且意外地由手势识别器处理。父(容器)控制器的根视图。我希望这些触摸被孩子的背景视图吞噬,以便忽略/取消它们。

我的第一个想法是覆盖子VC上的nextResponder以返回nil,假设这会阻止触摸事件传递给superview。没有成功,所以我尝试在子控制器上覆盖触摸处理方法(touchesBegan:等),但它们永远不会被调用。然后我将一个简单的UIView子类替换为我的子控制器的根视图,同样尝试这两种方法。再次为nextResponder返回nil没有任何效果,并且触摸方法永远不会被调用。

我的响应者链看起来完全按照我的预期设置:滚动视图 - >子VC的根视图 - >孩子VC - >父母的根视图 - >父VC。这让我觉得我的控制器包含设置正确,让我怀疑父母的根视图上的手势识别器以某种我不理解的方式以某种方式赢回响应者链。 / p>

这似乎应该很容易。我错过了什么?谢谢!

1 个答案:

答案 0 :(得分:1)

由于this very helpful WWDC video,我认为我更了解这里发生了什么。

鉴于传入的触摸,首先系统将该触摸与最深的经过测试的视图相关联;在我的情况下,这是UIScrollView。然后,它显然会回溯超级视图的层次结构,寻找任何其他附加的识别器。这一关键文档隐含了这种行为:

  

手势识别器针对特定视图以及该视图的所有子视图进行了热门测试。

滚动视图有自己的内部声像识别器,它可以取消无法识别的触摸,也可以回退到不会发生前进的响应器方法触及响应者链。这就解释了为什么我的响应器方法永远不会被调用,即使我自己的识别器被禁用了。

有了这些信息,我可以想出几种可能的方法来解决我的问题,例如:

  • 如果关联视图位于子控制器下,则使用手势委托方法忽略触摸。
  • 写一个" null"手势识别器子类捕获所有触摸并忽略它们,并将其附加到子控制器的根视图。

但我最终做的只是重新排列我的视图层次结构,顶部有一个新的空视图,这样我的子控制器视图可以是主内容视图的兄弟,而不是它的子视图。

因此视图层次结构会发生变化:

"Before" hierarchy

到此:

"After" hierarchy

这解决了我的问题:我的手势识别器不再与对儿童控制器视图进行过测试的触摸进行交互。而且我认为它可以更好地捕捉应用程序控制器之间的概念关系,而无需任何额外的逻辑。