所以我有一个视图控制器,它有一个容器视图。容器视图嵌入导航控制器,导航控制器也是视图控制器的父控制器。故事板是这样的:
视图控制器(mainViewController) -->导航控制器-->视图控制器(contentViewController)
你可以在下面看到故事板的截图。
第一个箭头是从容器视图到导航控制器的嵌入索引。第二个箭头是一个关系,表示contentViewController是导航控制器的根视图控制器。
mainViewController和contentViewController是同一个类的对象,名为testViewController。它是UIViewController的子类。它的实施很简单。它只有三个IBAction方法,没有其他方法。以下是实现代码:
#import "TestViewController.h"
@implementation TestViewController
- (IBAction)buttonTapped:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:@"button is tapped"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
- (IBAction)barButtonTapped:(id)sender
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:@"bar button is tapped"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
- (IBAction)viewTapped:(id)sender {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
message:@"view is tapped"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[alert show];
}
@end我在mainViewController的容器视图中添加了一个Tap手势识别器。当容器视图被点击时,它会将viewTapped:(id)sender消息发送给mainViewController。在contentViewController的根视图中,有一个按钮,当被点击时,该按钮向contentViewController发送buttonTapped:(id)sender消息。在contentViewController的工具栏上有一个bar按钮,当被点击时,它会向contentViewController发送barButtonTapped:(id)sender消息。最初的场景是mainViewController。当应用程序运行时,我发现只有bar按钮的触摸事件被阻塞,触摸事件被按钮正确地处理。在苹果的文档中,规管对意见的接触说:
在简单的情况下,当发生触摸时,将触摸对象从UIApplication对象传递给UIWindow对象。然后,在将触摸传递到视图对象本身之前,该窗口首先将触觉发送到任何附加于发生触摸的视图的手势识别器(或该视图的超级视图)。
我以为触摸事件不会传递到按钮。这让我很困惑。有人能解释一下这种行为吗?非常感谢。
故事板截图:

发布于 2014-09-27 22:53:09
iOS事件处理指南:事件传递:响应链的“响应链遵循特定的传递路径”部分描述了如何首先将触摸事件传递到被触摸的视图,然后通过其所有的超级视图向上传递,然后传递到窗口,最后传递到应用程序本身。
项目视图层次结构的简化表示形式如下:
mainViewController's Root View
| mainViewController's Container View (has Tap Gesture Recognizer)
| | UINavigationController's Root View
| | | contentViewController's View
| | | | UIButton ("Button")
| | | UINavigationController's Toolbar View
| | | | UIToolbarTextButton ("Item")...so当您点击按钮或工具栏按钮时,它们会在mainViewController的容器视图之前接收触摸事件。
按钮的事件触发和工具栏按钮的原因似乎与iOS事件处理指南:手势识别器的“与其他用户界面控件的交互”部分无关:
在iOS 6.0及更高版本中,默认控制操作防止重叠手势识别器行为。例如,按钮的默认操作是单个点击。如果在按钮的父视图上附加了一个点击手势识别器,并且用户点击按钮,则按钮的操作方法将接收触摸事件而不是手势识别器。
这似乎解释了为什么UIButton能够抢占点击手势识别器,但它没有说任何关于工具栏按钮的明确信息。
如果打印出视图层次结构,您会发现工具栏按钮是使用UIToolbarButton表示的,它是一个直接从UIControl继承的私有类。根据我们的观察,我们假设UIToolbarButton不会像公共UIControl子类那样抢占手势识别器。当我浏览它的touchesCancelled:withEvent:方法时,我发现它是在点击手势识别器触发之后被调用的,这似乎是您根据iOS事件处理指南所期望的:手势识别器的“手势识别器第一次有机会识别一个触摸”部分,他们注意到:
...if手势识别器识别触摸手势,然后窗口永远不会将触摸对象传递到视图,并且取消以前发送给视图的任何触摸对象,这些对象是该识别序列的一部分。
有几种不同的方法可以修改这种行为,而您选择的方式将取决于您的最终目标。如果希望允许触摸工具栏,可以检查发送给手势识别器的UITouch的gestureRecognizer:shouldReceiveTouch:是否位于工具栏的框架内,如果是,则返回NO。专门阻止对UIButton的触摸可能需要子类化,但是如果您想阻止对mainViewController的子视图控制器的所有触摸,您可以在其容器视图上添加一个透明的视图。
https://stackoverflow.com/questions/21317106
复制相似问题