使用容器视图附加的Tap Gesture Recognizer不会阻止容器视图中按钮的触摸事件,但会阻止工具栏按钮的触摸事件

时间:2014-01-23 19:01:28

标签: ios iphone event-handling uigesturerecognizer uicontainerview

所以我有一个视图控制器,它有一个容器视图。容器视图嵌入了导航控制器,导航控制器也是视图控制器的父控制器。故事板是这样的:

查看控制器(mainViewController) - >导航控制器 - >视图控制器(contentViewController

您可以在下面看到故事板的屏幕截图。

第一个箭头是从容器视图到导航控制器的嵌入segue。第二个箭头是表示contentViewController的关系,是导航控制器的根视图控制器。

mainViewControllercontentViewController是同一个类的对象,名为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对象。然后,窗口   首先将触摸发送到附加视图的任何手势识别器   在它通过之前发生的触摸(或对该视图的超视图)   触摸视图对象本身。

我认为触摸事件不会传递给按钮。这让我很困惑。有人可以解释这种行为吗?非常感谢你。


故事板的屏幕截图the storyboard

1 个答案:

答案 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的子视图控制器的所有触摸,你可以在其容器视图上添加透明视图。