所以我有一个视图控制器,它有一个容器视图。容器视图嵌入了导航控制器,导航控制器也是视图控制器的父控制器。故事板是这样的:
查看控制器(mainViewController
) - >导航控制器 - >视图控制器(contentViewController
)
您可以在下面看到故事板的屏幕截图。
第一个箭头是从容器视图到导航控制器的嵌入segue。第二个箭头是表示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 Gesture Recognizer。当点击容器视图时,它会向viewTapped:(id)sender
发送mainViewController
消息。在contentViewController
的根视图内部,有一个按钮可在点按时向buttonTapped:(id)sender
发送contentViewController
条消息。 contentViewController
工具栏中有一个条形按钮,在点击时会向barButtonTapped:(id)sender
发送contentViewController
条消息。初始场景为mainViewController
。当应用程序运行时,我发现只有条形按钮的触摸事件被阻止,触摸事件由按钮正确处理。在Apple的文档Regulating the Delivery of Touches to Views中,它说:
在简单的情况下,当发生触摸时,触摸对象被传递 从UIApplication对象到UIWindow对象。然后,窗口 首先将触摸发送到附加视图的任何手势识别器 在它通过之前发生的触摸(或对该视图的超视图) 触摸视图对象本身。
我认为触摸事件不会传递给按钮。这让我很困惑。有人可以解释这种行为吗?非常感谢你。
故事板的屏幕截图:
答案 0 :(得分:4)
Event Handling Guide for iOS: Event Delivery: The Responder Chain"响应者链遵循特定的传递路径" section描述了触摸事件如何首先传递到被触摸的视图,然后传递到所有超视图,然后传递到窗口,最后传递到应用程序本身。
项目视图层次结构的简化表示形式为:
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")
...所以当你点击按钮或工具栏按钮时,他们会在mainViewController的容器视图之前收到触摸事件。
按钮事件触发的原因以及工具栏按钮似乎与Event Handling Guide for iOS: Gesture Recognizers'无关。 "与其他用户界面控件进行交互"部分:
在iOS 6.0及更高版本中,默认控件操作可防止重叠手势识别器行为。例如,按钮的默认操作是单击。如果你有一个单击手势识别器附加到按钮的父视图,并且用户点击按钮,则按钮的动作方法接收触摸事件而不是手势识别器。
这似乎解释了UIButton
能够抢占点按手势识别器的原因,但它并没有明确说明工具栏按钮。
如果打印出视图层次结构,您会发现工具栏按钮是使用UIToolbarButton
表示的,UIControl
是一个直接从UIToolbarButton
继承的私有类。根据我们的观察,我们假设UIControl
不会像公共touchesCancelled:withEvent:
子类那样抢占手势识别器。当我调整它的UITouch
方法时,我发现它在点击手势识别器触发后被调用,这似乎是你所期望的基于iOS的事件处理指南:手势识别器"手势识别者获得第一个认识到触摸的机会"他们注意到的部分:
...如果手势识别器识别出触摸手势,则窗口永远不会将触摸对象传递给视图,并且还会取消先前发送到视图的任何触摸对象,这些触摸对象是该识别序列的一部分。
您可以通过几种不同的方式修改此行为,而您选择的行为取决于您的最终目标。如果您想允许工具栏上的触摸,您可以检查发送到手势识别器的代理gestureRecognizer:shouldReceiveTouch:
的{{1}}是否在工具栏的框架内并返回{ {1}}如果是的话。特此阻止对NO
的触摸可能需要子类化,但是如果你想阻止对mainViewController的子视图控制器的所有触摸,你可以在其容器视图上添加透明视图。