如何防止点击子视图触发父视图上的 UITapGestureRecognizer?

Posted

技术标签:

【中文标题】如何防止点击子视图触发父视图上的 UITapGestureRecognizer?【英文标题】:How do I prevent taps on a subview from triggering a UITapGestureRecognizer on a parent view? 【发布时间】:2016-03-31 02:05:16 【问题描述】:

我在视图中添加了一个点击识别器:

   UITapGestureRecognizer* tgr = [[UITapGestureRecognizer alloc]
      initWithTarget:self action:@selector( onTap )];
   [view addGestureRecognizer: tgr];

问题是点击view 的子视图会触发onTap。我该如何预防?

【问题讨论】:

【参考方案1】:

假设您的parentView 有一个subView。你实现了下面的UIGestureRecognizerDelegate方法,如果触摸在subView的范围内,你返回no。

tgr.delegate = self;

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

    CGPoint locationInView = [touch locationInView:self.parentView];
    if (CGRectContainsPoint(self.subView.frame, locationInView) ) 
        return NO;
     else 
        return YES;
    

【讨论】:

这对我来说似乎比批准的答案更好。阻止点击,而不是添加更多什么都不做的识别器。【参考方案2】:

将子视图添加到视图的背景,并将点击手势识别器附加到子视图:

UIView* subview = [[UIView alloc] initWithFrame:view.bounds];
subview.backgroundColor = [UIColor clearColor];//or view.backgroundColor
[view addSubview:subview];
[view sendSubviewToBack:subview];
[subview addGestureRecognizer:tapRecognizer];

【讨论】:

谢谢!即使在 Swift 4.0 中这也有效,这正是我正在寻找的一个简单的解决方案:) 我已经更改了代码,出现了一个小错误(您不应该使用视图的框架,使用边界来获取子视图的当前框架)。【参考方案3】:

AlertView 的 Swift 4.2 答案

添加手势识别器并设置委托:

let backgroundViewTapGesture = UITapGestureRecognizer(target: self, action: #selector(dismiss))
backgroundViewTapGesture.delegate = self     
self.backgroundView.addGestureRecognizer(backgroundViewTapGesture)
self.backgroundViewTapGesture = backgroundViewTapGesture

然后添加处理点击的扩展

extension AlertView: UIGestureRecognizerDelegate 

    // Only handle this for the background tap gesture
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool 
        guard gestureRecognizer == backgroundViewTapGesture, let backgroundView = gestureRecognizer.view, let alertView = self.alertContentView else 
            return true
        

        let touchLocation = touch.location(in: backgroundView)
        return !alertView.frame.contains(touchLocation)
    

【讨论】:

【参考方案4】:

在斯威夫特中:

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool 
    let locationInView = touch.location(in: mainView)
    if debugOptionsView.isHidden 
        return true
    
    return !debugOptionsView.frame.contains(locationInView)

【讨论】:

以上是关于如何防止点击子视图触发父视图上的 UITapGestureRecognizer?的主要内容,如果未能解决你的问题,请参考以下文章

如何在被父视图部分裁剪的子视图上触发 UITapGestureRecognizer?

单击子锚点时,如何防止触发父级的 onclick 事件?

防止子视图上的 UITapGestureRecognizer

iOS 子视图响应父视图的点击事件

如何将触摸事件从 ScrollView 子视图传递到它的父视图

防止父视图 UIGestureRecongnizer 在 UITableVIew 子视图中执行