容器视图附带的Tap Gesture Recognizer不会阻止容器视图中按钮的触摸事件,但会阻止工具栏按钮的触摸事件 [英] Tap Gesture Recognizer attached with container view does not block touch event of button in container view but blocks toolbar button's touch event

查看:83
本文介绍了容器视图附带的Tap Gesture Recognizer不会阻止容器视图中按钮的触摸事件,但会阻止工具栏按钮的触摸事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我有一个具有容器视图的视图控制器.容器视图嵌入有导航控制器,该导航控制器也是视图控制器的父控制器.故事板如下:

So I have a view controller which has a container view. The container view is embedded with a navigation controller which is also parent controller of a view controller. The storyboard is like this:

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

view controller(mainViewController) --> navigation controller --> view controller(contentViewController)

您可以在下面看到情节提要的屏幕截图.

You can see screenshot of storyboard in the below.

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

The first arrow is a embed segue from container view to navigation controller. The second arrow is a relationship represents contentViewController is root view controller of the navigation controller.

mainViewControllercontentViewController是同一类的对象,名为testViewController.它是UIViewController的子类.它的实现很简单.它只有三个IBAction方法,仅此而已.这是实现代码:

mainViewController and contentViewController are objects of the same class, named testViewController. It is the subclass of UIViewController. Its implementation is simple. It only has three IBAction methods, nothing else. Here is the implementation code:

#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.轻按容器视图时,它将向mainViewController发送viewTapped:(id)sender消息.在contentViewController的根视图内部,有一个按钮,可在点击该按钮时向contentViewController发送buttonTapped:(id)sender消息.在contentViewController的工具栏中有一个长条按钮,当点击该按钮时,该消息会向contentViewController发送barButtonTapped:(id)sender消息.初始场景为mainViewController.当应用程序运行时,我发现只有条形按钮的触摸事件被阻止,触摸事件才由按钮正确处理.在Apple文档中,

I added a Tap Gesture Recognizer to the container view in mainViewController. It sends viewTapped:(id)sender message to mainViewController when the container view is tapped. Inside of the root view of contentViewController, there is a button which sends buttonTapped:(id)sender message to contentViewController when tapped. And there is a bar button in the toolbar of contentViewController which sends barButtonTapped:(id)sender message to contentViewController when tapped. The initial scene is mainViewController. When the app is running, I found that only touch events of the bar button is blocked, touch event is handled correctly by the button. In Apple's documentation, Regulating the Delivery of Touches to Views, it says:

在简单的情况下,当发生触摸时,将传递触摸对象 从UIApplication对象到UIWindow对象.然后,窗户 首先将触摸发送到任何附加到视图的手势识别器,其中 在触摸通过之前发生了触摸(或该视图的超级视图) 对视图对象本身的触摸.

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.

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

I thought touch event will not pass to the button. This really confused me. Can someone explain this behavior? Thank you very much.

情节提要的屏幕截图:

推荐答案

The Event Handling Guide for iOS: Event Delivery: The Responder Chain's "The Responder Chain Follows a Specific Delivery Path" section describes how touch events are passed first to the view that was touched, then up through all of its superviews, then to the window, and finally to the application itself.

项目视图层次的简化表示为:

A simplified representation of your project's view hierarchy would be:

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的容器视图之前收到touch事件.

...so when you tap the button or the toolbar button, they receive the touch event before mainViewController's container view.

按钮事件触发而工具栏按钮未触发的原因似乎与

The reason why the button's event fires and the toolbar button's doesn't appears to be related to Event Handling Guide for iOS: Gesture Recognizers' "Interacting with Other User Interface Controls" section:

在iOS 6.0和更高版本中,默认控制动作可防止手势识别器行为重叠.例如,按钮的默认操作是单击.如果您在按钮的父视图上附加了一个点击手势识别器,并且用户点击了该按钮,则该按钮的操作方法将接收触摸事件,而不是手势识别器.

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能够抢占点击手势识别器的原因,但没有对工具栏按钮进行任何明确的说明.

That appears to explain why the UIButton is able to preempt the tap gesture recognizer, but it doesn't say anything explicit about the toolbar button.

如果打印出视图层次结构,您会发现使用UIToolbarButton表示工具栏按钮,该UIToolbarButton是直接从UIControl继承的私有类.根据我们的观察,我们假设UIToolbarButton不会像公共UIControl子类那样抢占手势识别器.当我滑动其touchesCancelled:withEvent:方法时,我发现它在轻击手势识别器触发后被调用,这似乎是您根据《 iOS事件处理指南》所期望的:手势识别器的手势识别器获得了第一个识别触摸的机会" 他们注意到的部分:

If you print out the view hierarchy you'll find that the toolbar button is represented using a UIToolbarButton which is a private class that inherits directly from UIControl. Based on our observations we would assume that UIToolbarButton does not preempt gesture recognizers like the public UIControl subclasses do. When I swizzled its touchesCancelled:withEvent: method I found that it gets called after the tap gesture recognizer fires, which seems to be what you would expect based on Event Handling Guide for iOS: Gesture Recognizers's "Gesture Recognizers Get the First Opportunity to Recognize a Touch" section where they note:

...如果手势识别器识别出触摸手势,则窗口将永远不会将触摸对象传递到视图,并且还会取消先前发送给视图的属于该识别序列的任何触摸对象.

...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.

您可以通过几种不同的方式来修改此行为,而选择的方式将取决于最终目标.如果要允许在工具栏上进行触摸,则可以检查发送到手势识别器的委托人gestureRecognizer:shouldReceiveTouch:UITouch是否在工具栏的框架内,如果是,则返回NO.专门阻止对UIButton的触摸可能需要子类化,但是如果您想阻止对mainViewController的子视图控制器的所有触摸,则可以在其容器视图上添加透明视图.

There are a few different ways you could modify this behavior and the one you picked would depend on your end goal. If you wanted to allow touches on the toolbar you could check if the UITouch sent to the gesture recognizer's delegate's gestureRecognizer:shouldReceiveTouch: was inside the toolbar's frame and return NO if it was. Blocking touches to the UIButton specifically would probably require subclassing, but if you wanted to block all touches to mainViewController's child view controllers you could add a transparent view over its container view.

这篇关于容器视图附带的Tap Gesture Recognizer不会阻止容器视图中按钮的触摸事件,但会阻止工具栏按钮的触摸事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆