首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >带有容器视图的点击手势记录器不会阻止容器视图中按钮的触摸事件,而是阻止工具栏按钮的触摸事件

带有容器视图的点击手势记录器不会阻止容器视图中按钮的触摸事件,而是阻止工具栏按钮的触摸事件
EN

Stack Overflow用户
提问于 2014-01-23 19:01:27
回答 1查看 4.4K关注 0票数 1

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

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

你可以在下面看到故事板的截图。

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

mainViewControllercontentViewController是同一个类的对象,名为testViewController。它是UIViewController的子类。它的实施很简单。它只有三个IBAction方法,没有其他方法。以下是实现代码:

代码语言:javascript
运行
复制
#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对象。然后,在将触摸传递到视图对象本身之前,该窗口首先将触觉发送到任何附加于发生触摸的视图的手势识别器(或该视图的超级视图)。

我以为触摸事件不会传递到按钮。这让我很困惑。有人能解释一下这种行为吗?非常感谢。

故事板截图

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-09-27 22:53:09

iOS事件处理指南:事件传递:响应链的“响应链遵循特定的传递路径”部分描述了如何首先将触摸事件传递到被触摸的视图,然后通过其所有的超级视图向上传递,然后传递到窗口,最后传递到应用程序本身。

项目视图层次结构的简化表示形式如下:

代码语言:javascript
运行
复制
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手势识别器识别触摸手势,然后窗口永远不会将触摸对象传递到视图,并且取消以前发送给视图的任何触摸对象,这些对象是该识别序列的一部分。

有几种不同的方法可以修改这种行为,而您选择的方式将取决于您的最终目标。如果希望允许触摸工具栏,可以检查发送给手势识别器的UITouchgestureRecognizer:shouldReceiveTouch:是否位于工具栏的框架内,如果是,则返回NO。专门阻止对UIButton的触摸可能需要子类化,但是如果您想阻止对mainViewController的子视图控制器的所有触摸,您可以在其容器视图上添加一个透明的视图。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21317106

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档