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

4ba*_*bar 5 uiviewcontroller uitouch uiresponder uigesturerecognizer ios

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

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

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

我的响应者链看起来完全按照我的预期设置:滚动视图 --> 子 VC 的根视图 --> 子 VC --> 父级的根视图 --> 父 VC。这让我认为我的控制器遏制设置正确,并让我怀疑父级根视图上的手势识别器以某种我不理解的方式赢得了响应者链。

这看起来应该很容易。我缺少什么?谢谢!

4ba*_*bar 4

我想我更好地理解了这里发生的事情,这要归功于这个非常有用的 WWDC 视频

\n\n

给定一个传入触摸,系统首先将该触摸与最深的命中测试视图相关联;就我而言,这就是 UIScrollView。然后它显然会沿着超级视图的层次结构向上走,寻找任何其他附加的识别器。文档的这个关键部分暗示了这种行为:

\n\n
\n

手势识别器对特定视图和所有该视图\xe2\x80\x99s 子视图进行命中测试的触摸进行操作进行命中测试的触摸进行操作。

\n
\n\n

滚动视图有自己的内部平移识别器,它要么取消无法识别的触摸,要么可能回退到不会碰巧向前触摸响应程序链的响应程序方法。这解释了为什么即使我自己的识别器被禁用,我的响应程序方法也永远不会被调用。

\n\n

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

\n\n
    \n
  • 如果/当关联视图位于子控制器下时,使用手势委托方法来忽略触摸。
  • \n
  • 编写一个“空”手势识别器子类来捕获所有触摸并忽略它们,并将其附加到子控制器的根视图。
  • \n
\n\n

但我最终所做的只是重新排列视图层次结构,在顶部添加一个新的空视图,以便我的子控制器视图可以是主内容视图的同级视图,而不是其子视图。

\n\n

所以视图层次结构从此改变:

\n\n

“之前”的层次结构

\n\n

对此:

\n\n

“之后”层次结构

\n\n

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

\n