UIGestureRecognizer阻止子视图处理触摸事件

我试图弄清楚这是如何做到正确的 。 我试图描绘的情况: 在这里输入图像说明

我添加一个UITableView作为UIView的子视图。 UIView响应pinchGestureRecognizerpinchGestureRecognizer ,但是当这样做时,tableview停止对这两个手势作出反应(它仍然对滑动作出反应)。

我已经使它与下面的代码工作,但它显然不是一个很好的解决scheme,我敢肯定有一个更好的方法。 这是放在UIView (超级视图):

 -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if([super hitTest:point withEvent:event] == self) { for (id gesture in self.gestureRecognizers) { [gesture setEnabled:YES]; } return self; } for (id gesture in self.gestureRecognizers) { [gesture setEnabled:NO]; } return [self.subviews lastObject]; } 

我有一个非常类似的问题,并find我的解决scheme在这个SO问题 。 总之,将自己设置为您的UIGestureRecognizer ,然后在允许识别器处理触摸之前检查目标视图。 相关的委托方法是:

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

将触摸事件阻塞到子视图是默认行为。 你可以改变这个行为:

 UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)]; r.cancelsTouchesInView = NO; [agentPicker addGestureRecognizer:r]; 

一种可能是你的手势识别器子类(如果你还没有),并覆盖-touchesBegan:withEvent:这样它确定每个触摸开始在一个排除的子视图,并调用-ignoreTouch:forEvent:如果它触摸。

显然,您还需要添加一个属性来跟踪排除的子视图,或者更好的方法是排除一些子视图。

我正在显示一个有自己的tableview下拉子视图。 因此, touch.view有时会返回像UITableViewCell这样的类。 我必须通过超类(ES)来确保它是我认为是的子类:

 -(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { UIView *view = touch.view; while (view.class != UIView.class) { // Check if superclass is of type dropdown if (view.class == dropDown.class) { // dropDown is an ivar; replace with your own NSLog(@"Is of type dropdown; returning NO"); return NO; } else { view = view.superview; } } return YES; } 

有可能没有inheritance任何类。

您可以在手势的callbackselect器中检查gestureRecognizers

如果view.gestureRecognizers不包含您的gestureRecognizer,只是忽略它

例如

 - (void)viewDidLoad { UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; singleTapGesture.numberOfTapsRequired = 1; } 

在这里检查view.gestureRecognizers

 - (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer { UIEvent *event = [[UIEvent alloc] init]; CGPoint location = [gestureRecognizer locationInView:self.view]; //check actually view you hit via hitTest UIView *view = [self.view hitTest:location withEvent:event]; if ([view.gestureRecognizers containsObject:gestureRecognizer]) { //your UIView //do something } else { //your UITableView or some thing else... //ignore } } 

我创build了一个UIGestureRecognizer子类,用于阻止连接到特定视图的超级视图的所有手势识别器。

这是我的WEPopover项目的一部分。 你可以在这里find它。

我也在做一个popover,这是我做的

 func didTap(sender: UITapGestureRecognizer) { let tapLocation = sender.locationInView(tableView) if let _ = tableView.indexPathForRowAtPoint(tapLocation) { sender.cancelsTouchesInView = false } else { delegate?.menuDimissed() } } 

你可以把它closures和….在我的代码我做了这样的事情,因为我需要把它closures时,键盘不显示,你可以将其应用于您的情况:

调用这个是viewdidload等:

 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; [center addObserver:self selector:@selector(notifyShowKeyboard:) name:UIKeyboardDidShowNotification object:nil]; [center addObserver:self selector:@selector(notifyHideKeyboard:) name:UIKeyboardWillHideNotification object:nil]; 

然后创build两个方法:

 -(void) notifyShowKeyboard:(NSNotification *)inNotification { tap.enabled=true; // turn the gesture on } -(void) notifyHideKeyboard:(NSNotification *)inNotification { tap.enabled=false; //turn the gesture off so it wont consume the touch event } 

这是做什么是禁用水龙头。 我不得不把自来水变成一个实例variables,并释放它在dealloc虽然。

为parentView的所有识别器实现委托,并将gestureRecognizer方法放入负责同时触发识别器的委托中:

 func gestureRecognizer(UIGestureRecognizer, shouldBeRequiredToFailByGestureRecognizer:UIGestureRecognizer) -> Bool { if (otherGestureRecognizer.view.isDescendantOfView(gestureRecognizer.view)) { return true } else { return false } 

}

你可以使用失败的方法,如果你想让孩子被触发,但不是父识别器:

https://developer.apple.com/reference/uikit/uigesturerecognizerdelegate

build立在@Pin Shih王回答 。 我们忽略除包含轻击手势识别器的视图以外的所有轻敲。 所有的水龙头都像往常一样正常转发到视图层次,因为我们已经设置了tapGestureRecognizer.cancelsTouchesInView = false 。 这是Swift3 / 4中的代码:

 func ensureBackgroundTapDismissesKeyboard() { let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap)) tapGestureRecognizer.cancelsTouchesInView = false self.view.addGestureRecognizer(tapGestureRecognizer) } @objc func handleTap(recognizer: UIGestureRecognizer) { let location = recognizer.location(in: self.view) let hitTestView = self.view.hitTest(location, with: UIEvent()) if hitTestView?.gestureRecognizers?.contains(recognizer) == .some(true) { // I dismiss the keyboard on a tap on the scroll view // REPLACE with own logic self.view.endEditing(true) } }