82

我试图弄清楚这是如何以正确的方式完成的。我试图描述这种情况: 在此处输入图像描述

我正在添加 aUITableView作为 a 的子视图UIViewUIView响应点击和,但是这样pinchGestureRecognizer做时,表格视图停止对这两个手势做出反应(它仍然对滑动做出反应)。

我已经使用以下代码使其工作,但这显然不是一个好的解决方案,我相信有更好的方法。这放在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];
}
4

10 回答 10

182

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

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch
于 2011-05-04T17:35:00.883 回答
109

阻止触摸事件到子视图是默认行为。您可以更改此行为:

UITapGestureRecognizer *r = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(agentPickerTapped:)];
r.cancelsTouchesInView = NO;
[agentPicker addGestureRecognizer:r];
于 2012-07-20T06:05:54.253 回答
5

我正在显示一个具有自己的表格视图的下拉子视图。结果,touch.view有时会返回诸如UITableViewCell. 我必须逐步检查超类以确保它是我认为的子类:

-(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;
}
于 2013-07-24T11:43:30.437 回答
5

以@Pin Shih Wang回答为基础。除了包含点击手势识别器的视图上的点击之外,我们忽略所有点击。所有的点击都像我们设置的一样被转发到视图层次结构中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)
    }
}
于 2017-09-27T12:33:54.703 回答
4

一种可能性是将您的手势识别器子类化(如果您还没有)并覆盖-touchesBegan:withEvent:,以便它确定每个触摸是否从排除的子视图开始,-ignoreTouch:forEvent:如果是,则调用该触摸。

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

于 2011-03-08T15:49:39.490 回答
2

可以不继承任何类。

您可以在手势的回调选择器中检查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
    }
}
于 2014-04-14T05:09:40.650 回答
1

我创建了一个 UIGestureRecognizer 子类,旨在阻止所有附加到特定视图的超级视图的手势识别器。

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

于 2014-09-18T14:56:27.927 回答
1

为 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

于 2016-12-12T11:01:32.927 回答
0

您可以将其关闭和打开....在我的代码中,我做了类似的事情,因为我需要在键盘未显示时将其关闭,您可以将其应用于您的情况:

称之为 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];

然后创建两个方法:

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

这样做是禁用水龙头。我不得不把 tap 变成一个实例变量并在 dealloc 中释放它。

于 2012-12-01T04:12:10.870 回答
0

我也在做一个弹出窗口,这就是我做的

func didTap(sender: UITapGestureRecognizer) {

    let tapLocation = sender.locationInView(tableView)

    if let _ = tableView.indexPathForRowAtPoint(tapLocation) {
        sender.cancelsTouchesInView = false
    }
    else {
        delegate?.menuDimissed()
    }
}
于 2015-10-29T20:06:01.143 回答