ios - 与容器 View 连接的点击手势识别器不会阻止容器 View 中按钮的触摸事件,但会阻止工具栏按钮的触摸事件

标签 ios iphone event-handling uigesturerecognizer uicontainerview

所以我有一个 View Controller ,它有一个容器 View 。容器 View 嵌入了导航 Controller ,该 Controller 也是 View Controller 的父 Controller 。 Storyboard是这样的:

View Controller ( mainViewController ) --> 导航 Controller --> View Controller ( contentViewController )

您可以在下面看到 Storyboard的屏幕截图。

第一个箭头是从容器 View 到导航 Controller 的嵌入序列。第二个箭头是一个关系,代表contentViewController是导航 Controller 的 Root View Controller 。
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 中的容器 View 中添加了一个点击手势识别器.它发送viewTapped:(id)sendermainViewController 留言当点击容器 View 时。 contentViewController 的 Root View 内部,有一个按钮发送buttonTapped:(id)sendercontentViewController 留言轻按时。在contentViewController的工具栏中有一个条形按钮发送barButtonTapped:(id)sendercontentViewController 留言轻按时。初始场景是mainViewController .当应用程序运行时,我发现只有栏按钮的触摸事件被阻止,触摸事件被按钮正确处理。在 Apple 的文档中,Regulating the Delivery of Touches to Views , 它说:

In the simple case, when a touch occurs, the touch object is passed from the UIApplication object to the UIWindow object. Then, the window first sends touches to any gesture recognizers attached the view where the touches occurred (or to that view’s superviews), before it passes the touch to the view object itself.



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

Storyboard截图 :
the storyboard

最佳答案

Event Handling Guide for iOS: Event Delivery: The Responder Chain的“响应者链遵循特定的传递路径”部分描述了触摸事件如何首先传递到被触摸的 View ,然后向上通过其所有 super View ,然后传递到窗口,最后传递到应用程序本身。

项目 View 层次结构的简化表示形式为:

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 的容器 View 之前收到触摸事件。

按钮的事件触发而工具栏按钮似乎与 Event Handling Guide for iOS: Gesture Recognizers 无关的原因'“与其他用户界面控件交互”部分:

In iOS 6.0 and later, default control actions prevent overlapping gesture recognizer behavior. For example, the default action for a button is a single tap. If you have a single tap gesture recognizer attached to a button’s parent view, and the user taps the button, then the button’s action method receives the touch event instead of the gesture recognizer.



这似乎解释了为什么 UIButton能够抢占轻击手势识别器,但它没有明确说明工具栏按钮。

如果您打印出 View 层次结构,您会发现工具栏按钮使用 UIToolbarButton 表示。这是一个直接继承自 UIControl 的私有(private)类.根据我们的观察,我们假设 UIToolbarButton不像公众那样抢占手势识别器UIControl子类做。当我调配它的 touchesCancelled:withEvent:方法我发现它在点击手势识别器触发后被调用,这似乎是您根据 iOS 事件处理指南所期望的:手势识别器的“手势识别器获得第一个识别触摸的机会”部分,他们注意到:

...if the gesture recognizer recognizes a touch gesture, then the window never delivers the touch object to the view, and also cancels any touch objects it previously sent to the view that were part of that recognized sequence.



有几种不同的方法可以修改此行为,您选择的方法取决于您的最终目标。如果您想允许触摸工具栏,您可以检查 UITouch发送到手势识别器的代表gestureRecognizer:shouldReceiveTouch:在工具栏的框架内并返回 NO如果它是。阻止对 UIButton 的触摸特别是可能需要子类化,但是如果您想阻止对 mainViewController 的 subview Controller 的所有触摸,您可以在其容器 View 上添加一个透明 View 。

关于ios - 与容器 View 连接的点击手势识别器不会阻止容器 View 中按钮的触摸事件,但会阻止工具栏按钮的触摸事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21317106/

相关文章:

ios - 核心数据中的 SQL 请求

ios - 在 Swift 中拉伸(stretch)背景以查看

iphone - iOS CALayer 内存泄漏仅在设备上

iphone - 为什么我的 3D 旋转图像与另一幅图像相交?

delphi - 有没有办法在 Delphi 中找到未使用的事件处理程序?

ios - ios UIView动画(onUpdate)

ios - 从 URL 延迟获取图像

ios - 如何区分调用 didEnterRegion 的 CLCircularRegion 和 CLBeaconRegion

JAVASCRIPT:尝试在自定义事件调度程序上创建 hasCallbackFor 函数

java - 处理 JButton 集合的事件