【问题标题】:Gesture recognizer and button actions手势识别器和按钮操作
【发布时间】:2011-06-17 01:08:43
【问题描述】:

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

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

【问题讨论】:

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

标签: iphone uibutton conflict uigesturerecognizer ibaction


【解决方案1】:

在“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 才能使其正常工作。

沙尼

【讨论】:

  • 啊!!!是的,我忘记了这个 -gestureRecognizer:shouldReceiveTouch: 方法。感谢您为我指明正确的方向。虽然这解决了我的问题,但我仍然不知道为什么响应者层次结构在这种情况下不起作用。它可能应该,但它没有被 Apple 处理。
  • UIGestureRecognizer 行为被清楚地描述为与“正常”响应者链分开。这是 Apple 的设计决定。
  • 记得遵守 UIGestureRecognizerDelegate 协议并将 UIGestureRecognizer 的委托设置为该对象。
  • 为了更广泛的使用,请考虑 Ramesh 或 flypig 的测试子句的一些变体。例如,在我的情况下,我最终得到了以下行:if ( [touch.view isKindOfClass:[UIControl class]] || [[touch.view superview] isKindOfClass:[UITableViewCell class]] ) {... 请注意,tableview 单元格在它们的 contentView 中被“触及”,它是私有类的成员,所以我们在那里检查 superview 的类。
  • 感谢您的回答!就我而言,我遇到了同样的问题,但直到我在实际设备中进行测试才发现它。在模拟器中运行应用程序而不使用 UIGestureDelegate 如this answer所示按预期工作,但不正确。
【解决方案2】:

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

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

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

现在完美运行......

【讨论】:

  • 我只错过了myGestureRecognizer.delegate = self;
【解决方案3】:

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

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

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

【讨论】:

    【解决方案4】:

    这里是 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)

    【讨论】:

      【解决方案5】:

      我认为最好的解决方案是使用下面的代码 sn-p:

      -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
          CGPoint touchLocation = [touch locationInView:self.view];
          return !CGRectContainsPoint(self.menuButton.frame, touchLocation);
      }
      

      【讨论】:

        【解决方案6】:

        这是一个 Swift 版本:

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

        别忘了:

        1. 让你的班级符合UIGestureRecognizerDelegate
        2. 让你的 Tapper 对象委托给自己(例如:tapper.delegate = self

        【讨论】:

          【解决方案7】:

          Vivienne 的 Swift 版本回答:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-08-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-07-13
            • 1970-01-01
            相关资源
            最近更新 更多