手势识别器和按钮动作


99

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

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)内的Rounded Rect Button采取任何操作。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;
    }
}

最简单的方法是设置cancelsTouchesInView = false
Bagusflyer

Answers:


176

在“ 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;
}

希望对你有帮助

编辑

正如丹尼尔(Daniel)指出的那样,您必须遵守UIGestureRecognizerDelegate它才能正常工作。

沙尼


1
啊!!!是的,我忘了这个-gestureRecognizer:shouldReceiveTouch:方法。感谢您指出正确的方向。尽管这解决了我的问题,但是我仍然不知道为什么在这种情况下响应器层次结构无法正常工作。它可能应该,但是Apple并没有对其进行处理。
Mustafa

2
UIGestureRecognizer的行为清楚地描述为与“正常”响应者链不同。这是Apple的设计决定。
Sylvain G.

11
请记住要遵守UIGestureRecognizerDelegate协议,并将UIGestureRecognizer的委托设置为该对象。
丹尼尔(Daniel)

2
为了更广泛地使用,请考虑Ramesh或flypig的test子句的某些变体。例如,在我的情况下,我以以下一行结束:if ( [touch.view isKindOfClass:[UIControl class]] || [[touch.view superview] isKindOfClass:[UITableViewCell class]] ) {...请注意,tableview单元在其contentView中被“触摸”,它是私有类的成员,因此我们在那里检查superview的类。
clozach 2012年

谢谢您的回答!就我而言,我遇到了同样的问题,但是直到在实际设备中进行测试之前,我才发现它。如错误答案所示,在模拟器中运行应用程序而不使用UIGestureDelegate(如此答案所示)可以正常工作。
Luis Artola

51

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

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

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

现在可以正常工作了............


4
我只错过了myGestureRecognizer.delegate = self;
zero3nna 2013年

20

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

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

注意:请勿执行这个检查(检查Recognirer.view类类型)的gestureRecognizerShouldBegin,它将无法工作。


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)


6

这是Swift版本:

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

不要忘记:

  1. 使您的课堂符合 UIGestureRecognizerDelegate
  2. 让你的攻丝机的对象授人以自我(如:tapper.delegate = self

5

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

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    CGPoint touchLocation = [touch locationInView:self.view];
    return !CGRectContainsPoint(self.menuButton.frame, touchLocation);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.