194

我有一个视图UITapGestureRecognizer。因此,当我点击视图时,该视图上方会出现另一个视图。这个新视图有三个按钮。当我现在按下这些按钮之一时,我没有得到按钮动作,我只得到点击手势动作。所以我不能再使用这些按钮了。我该怎么做才能让事件通过这些按钮?奇怪的是按钮仍然突出显示。

在收到点击后,我不能只删除 UITapGestureRecognizer。因为有了它,新视图也可以被删除。意味着我想要像全屏视频控件这样的行为

4

12 回答 12

261

您可以将控制器或视图(无论哪个创建手势识别器)设置为UITapGestureRecognizer. 然后在委托中你可以实现-gestureRecognizer:shouldReceiveTouch:. 在您的实现中,您可以测试触摸是否属于您的新子视图,如果是,则指示手势识别器忽略它。类似于以下内容:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    // test if our control subview is on-screen
    if (self.controlSubview.superview != nil) {
        if ([touch.view isDescendantOfView:self.controlSubview]) {
            // we touched our control surface
            return NO; // ignore the touch
        }
    }
    return YES; // handle the touch
}
于 2010-07-27T22:29:17.563 回答
159

作为凯西对凯文巴拉德回答的后续行动:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
        if ([touch.view isKindOfClass:[UIControl class]]) {
            // we touched a button, slider, or other UIControl
            return NO; // ignore the touch
        }
    return YES; // handle the touch
}

这基本上使所有用户输入类型的控件(如按钮、滑块等)都能正常工作

于 2011-09-05T04:14:56.337 回答
107

在这里找到了这个答案:链接

你也可以使用

tapRecognizer.cancelsTouchesInView = NO;

这可以防止敲击识别器成为唯一捕获所有敲击的识别器

更新 - Michael提到了描述此属性的文档的链接:cancelsTouchesInView

于 2012-01-17T07:28:02.567 回答
72

作为凯文巴拉​​德的回答的后续行动,我遇到了同样的问题并最终使用了这段代码:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if ([touch.view isKindOfClass:[UIButton class]]){
        return NO;
    }
    return YES;
}

它具有相同的效果,但这将适用于任何视图深度的任何 UIButton(我的 UIButton 有几个视图深度,并且 UIGestureRecognizer 的委托没有对它的引用。)

于 2011-07-13T22:21:47.740 回答
10

在 iOS 6.0 及更高版本中,默认控制操作可防止重叠的手势识别器行为。例如,按钮的默认操作是单击。如果您将单击手势识别器附加到按钮的父视图,并且用户点击按钮,则按钮的操作方法会接收触摸事件而不是手势识别器。这仅适用于与控件的默认操作重叠的手势识别,其中包括:......

来自 Apple 的 API 文档

于 2013-11-20T10:16:58.117 回答
8

这些答案是不完整的。我不得不阅读多篇关于如何使用这个布尔运算的帖子。

在你的 *.h 文件中添加这个

@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>

在你的 *.m 文件中添加这个

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {

    NSLog(@"went here ...");

    if ([touch.view isKindOfClass:[UIControl class]])
    {
        // we touched a button, slider, or other UIControl
        return NO; // ignore the touch
    }
    return YES; // handle the touch
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.



    //tap gestrure
    UITapGestureRecognizer *tapGestRecog = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(screenTappedOnce)];
    [tapGestRecog setNumberOfTapsRequired:1];
    [self.view addGestureRecognizer:tapGestRecog];


// This line is very important. if You don't add it then your boolean operation will never get called
tapGestRecog.delegate = self;

}


-(IBAction) screenTappedOnce
{
    NSLog(@"screenTappedOnce ...");

}
于 2013-08-18T23:51:17.967 回答
7

从这里找到了另一种方法。它检测触摸是否在每个按钮内。

(1) pointInside:withEvent: (2) locationInView:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
       shouldReceiveTouch:(UITouch *)touch {
    // Don't recognize taps in the buttons
    return (![self.button1 pointInside:[touch locationInView:self.button1] withEvent:nil] &&
            ![self.button2 pointInside:[touch locationInView:self.button2] withEvent:nil] &&
            ![self.button3 pointInside:[touch locationInView:self.button3] withEvent:nil]);
}
于 2011-08-08T12:53:28.317 回答
7

斯威夫特 5

带有 Tapgesture 的超级视图上的按钮

 func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if let _ = touch.view as? UIButton { return false }
    return true
}

就我而言,实施hitTest对我有用。我有带有按钮的收藏视图

该方法通过调用point(inside:with:)每个子视图的方法来遍历视图层次结构,以确定哪个子视图应该接收触摸事件。如果point(inside:with:)返回 true,则类似地遍历子视图的层次结构,直到找到包含指定点的最前面的视图。

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    guard isUserInteractionEnabled else { return nil }

    guard !isHidden else { return nil }

    guard alpha >= 0.01 else { return nil }

    guard self.point(inside: point, with: event) else { return nil }

    for eachImageCell in collectionView.visibleCells {
        for eachImageButton in eachImageCell.subviews {
            if let crossButton = eachImageButton as? UIButton {
                if crossButton.point(inside: convert(point, to: crossButton), with: event) {
                    return crossButton
                }
            }
        }
    }
    return super.hitTest(point, with: event)
}
于 2019-12-05T23:07:06.783 回答
3

这是对我有用的 Lily Ballard 答案的 Swift 版本:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (scrollView.superview != nil) {
        if ((touch.view?.isDescendantOfView(scrollView)) != nil) { return false }
    }
    return true
}
于 2016-06-02T15:18:41.180 回答
1

如果你的场景是这样的:

您有一个简单的视图和一些 UIButtons、UITextField 控件作为子视图添加到该视图。现在,当您触摸视图上除控件(您添加的子视图)之外的任何其他位置时,您想要关闭键盘

那么解决方案是:

将以下方法添加到您的 XYZViewController.m(有您的视图)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}
于 2013-05-23T06:22:38.910 回答
1

您可以通过设置以下布尔值来阻止 UITapGestureRecognizer 取消其他事件(例如点击按钮):

    [tapRecognizer setCancelsTouchesInView:NO];
于 2013-05-17T11:34:52.230 回答
1

优化 cdasher 的答案,你得到

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch 
{
    return ![touch.view isKindOfClass:[UIControl class]];
}
于 2015-11-13T17:03:28.013 回答