100

我有一个看起来像这样的视图层次结构:

UIView (A)
UIView > UIImageView
UIView > UIView (B)
UIView > UIView (B) > Rounded Rect Button
UIView > UIView (B) > UIImageView
UIView > UIView (B) > UILabel

我已将手势识别器附加到我的 UIView (B)。我面临的问题是我没有对 UIView (B) 内的圆角矩形按钮进行任何操作。singleTap 手势识别器捕获/覆盖按钮的 Touch Up Inside 事件。

我怎样才能让它工作?我认为响应者链层次结构将确保按钮触摸事件将被优先考虑,并且它将被触发!我错过了什么?

下面是一些相关代码:

#pragma mark -
#pragma mark View lifecycle (Gesture recognizer setup)

- (void)viewDidLoad {
    [super viewDidLoad];

    // double tap gesture recognizer
    UITapGestureRecognizer *dtapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapGestureRecognizer:)];
    dtapGestureRecognize.delegate = self;
    dtapGestureRecognize.numberOfTapsRequired = 2;
    [self.viewB addGestureRecognizer:dtapGestureRecognize];

    // single tap gesture recognizer
    UITapGestureRecognizer *tapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapGestureRecognizer:)];
    tapGestureRecognize.delegate = self;
    tapGestureRecognize.numberOfTapsRequired = 1;
    [tapGestureRecognize requireGestureRecognizerToFail:dtapGestureRecognize];
    [self.viewB addGestureRecognizer:tapGestureRecognize];

    // add gesture recodgnizer to the grid view to start the edit mode
    UILongPressGestureRecognizer *pahGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognizerStateChanged:)];
    pahGestureRecognizer.delegate = self;
    pahGestureRecognizer.minimumPressDuration = 0.5;
    [self.viewB addGestureRecognizer:pahGestureRecognizer];

    [dtapGestureRecognize release];
    [tapGestureRecognize release];
    [pahGestureRecognizer release];
}

#pragma mark -
#pragma mark Button actions

- (IBAction)buttonTouchUpInside:(id)sender {
    NSLog(@"%s, %@", __FUNCTION__, sender);
}

#pragma mark -
#pragma mark Gesture recognizer actions


- (void)singleTapGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    NSLog(@"%s", __FUNCTION__);
}

- (void)doubleTapGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    NSLog(@"%s", __FUNCTION__);
}

- (void)longPressGestureRecognizerStateChanged:(UIGestureRecognizer *)gestureRecognizer {

    switch (gestureRecognizer.state) {

        case UIGestureRecognizerStateEnded: {
            NSLog(@"%s", __FUNCTION__);

            break;
        }
        default:
            break;
    }
}
4

9 回答 9

179

在“shouldReceiveTouch”方法中,您应该添加一个条件,如果触摸在按钮中,则该条件将返回 NO。

这是来自苹果SimpleGestureRecognizers的例子。

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

    // Disallow recognition of tap gestures in the segmented control.
    if ((touch.view == yourButton)) {//change it to your condition
        return NO;
    }
    return YES;
}

希望它会有所帮助

编辑

正如丹尼尔所说,你必须遵守UIGestureRecognizerDelegate它才能工作。

沙尼

于 2011-01-28T05:49:34.240 回答
51

我也有同样的问题,然后我尝试了

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

    if ([touch.view isKindOfClass:[UIButton class]]) {      //change it to your condition
        return NO;
    }
    return YES;
}

它现在完美地工作......

于 2011-07-26T05:53:06.810 回答
20

一般来说,我们使用下面的委托方法来避免各种 UIControls 中的触摸:

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

注意:不要做这个检查(检查recognizer.view 类类型)gestureRecognizerShouldBegin,它不会工作。

于 2012-09-04T07:53:08.853 回答
11

这是一个Swift 3.0版本:

extension UIViewController: UIGestureRecognizerDelegate {

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view is UIButton {
        return false
    }
    return true
}

不要忘记:

Make your tapper object delegate to self (e.g: tapper.delegate = self)

于 2016-12-07T16:12:37.357 回答
6

在我看来,最好的解决方案是使用下面的代码片段:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    CGPoint touchLocation = [touch locationInView:self.view];
    return !CGRectContainsPoint(self.menuButton.frame, touchLocation);
}
于 2014-11-10T15:56:27.353 回答
6

这是一个斯威夫特版本:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (touch.view!.isKindOfClass(UIButton)) {
        return false
    }
    return true
}

不要忘记:

  1. 让你的课堂符合UIGestureRecognizerDelegate
  2. 让你的 Tapper 对象委托给自己(例如tapper.delegate = self:)
于 2015-12-28T19:28:14.863 回答
0

Vivienne 的 Swift 版本回答:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    let location = touch.location(in: view)
    return !someView.frame.contains(location)
}
于 2021-12-22T04:42:01.573 回答
0

对于委托中的 Swift 5,您只需添加:

return (touch.view is UIButton) ? false : true
于 2022-02-13T08:12:12.917 回答
0

我的情况如下:

UIView (with tap gesture)
├-> UIView (named "textFieldView")
    ├-> UIControl
    ├-> UITextField
    ├-> UIView (over the textField, with a tap gesture)

╭──────────────────────────────╮
│ ╭──────────────────────────╮ │
│ │ ╭──╮  ┌╴╶╴╶╴╶╴╶╴╶╴╶╴╶╴╶┐ │ │
│ │ ╰──╯  └╴╶╴╶╴╶╴╶╴╶╴╶╴╶╴╶┘ │ │
│ ╰──────────────────────────╯ │
└──────────────────────────────┘

上部 UIView 上的 tapGesture 导致与 UIControl 目标发生冲突。如果目标是使用touchDown(但不调用touchUpInside)设置的,或者如果我将继承从 更改为UIControlUIButton同时将目标设置保持在 event ,则调用目标touchUpInside

我要解决的问题是:将上视图设置为其点击手势的代表。功能func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool是这样实现的(在上层 UIView 中):

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    let touchLocationRelatedToTextFieldView = touch.location(in: textFieldView)
    return textFieldView.frame.contains(touchLocationRelatedToTextFieldView) == false
}

通过实现该委托功能,我现在能够保持我的 UIControl 和目标设置打开touchUpInside!:)

于 2022-02-16T10:06:05.217 回答