UITapGestureRecognizer点击self.view但忽略子视图

时间:2013-04-04 14:53:47

标签: ios uitapgesturerecognizer

当我双击self.view(UIViewCotroller的视图)时,我需要实现一个将调用某些代码的功能。但是我在这个视图上有其他UI对象的问题,我不想将任何识别器对象附加到所有这些对象上。我在下面找到了这个方法如何在我的视图上做手势,我知道它是如何工作的。现在我在障碍面前选择哪种方式来创建忽略子视图的识别器。有任何想法吗?感谢。

UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
[self.view addGestureRecognizer:doubleTap];

12 个答案:

答案 0 :(得分:118)

您应该在UIGestureRecognizerDelegate对象中采用self协议,并调用以下方法来检查视图。在此方法中,检查您对touch.view的视图并返回相应的bool(是/否)。像这样:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    if ([touch.view isDescendantOfView:yourSubView]) {
        return NO;
    }
    return YES;
}
编辑:请同时查看@ Ian的回答!

答案 1 :(得分:85)

另一种方法是仅比较触摸视图是否为手势视图,因为后代不会通过该条件。一个漂亮,简单的单行:

ng-model="selectedQuantity"

答案 2 :(得分:18)

对于Swift变种:

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

很高兴知道,isDescendantOfView返回一个Boolean值,表示接收者是给定视图的子视图还是与该视图相同。

答案 3 :(得分:7)

完整的快速解决方案(代理必须实现并设置为识别器):

class MyViewController: UIViewController UIGestureRecognizerDelegate {

    override func viewDidLoad() {
        let doubleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(onBaseTapOnly))
        doubleTapRecognizer.numberOfTapsRequired = 2
        doubleTapRecognizer.delegate = self
        self.view.addGestureRecognizer(doubleTapRecognizer)
    }

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

    func onBaseTapOnly(sender: UITapGestureRecognizer) {
        if sender.state == .Ended {
            //react to tap
        }
    }
}

答案 4 :(得分:4)

在iOS 11和Swift 4.2中,UIGestureRecognizerDelegate有一个名为gestureRecognizer(_:shouldReceive:)的方法。 gestureRecognizer(_:shouldReceive:)具有以下声明:

  

询问代表是否手势识别器应该接收到代表触摸的对象。

optional func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool

下面的完整代码显示了gestureRecognizer(_:shouldReceive:)的可能实现。使用此代码,点击ViewController的视图的子视图(包括imageView)将不会触发printHello(_:)方法。

import UIKit

class ViewController: UIViewController, UIGestureRecognizerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()

        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(printHello))
        tapGestureRecognizer.delegate = self
        view.addGestureRecognizer(tapGestureRecognizer)

        let imageView = UIImageView(image: UIImage(named: "icon")!)
        imageView.frame = CGRect(x: 50, y: 50, width: 100, height: 100)
        view.addSubview(imageView)

        // ⚠️ Enable user interaction for imageView so that it can participate to touch events.
        // Otherwise, taps on imageView will be forwarded to its superview and managed by it.
        imageView.isUserInteractionEnabled = true
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        // Prevent subviews of a specific view to send touch events to the view's gesture recognizers.
        if let touchedView = touch.view, let gestureView = gestureRecognizer.view, touchedView.isDescendant(of: gestureView), touchedView !== gestureView {
            return false
        }
        return true
    }

    @objc func printHello(_ sender: UITapGestureRecognizer) {
        print("Hello")
    }

}

gestureRecognizer(_:shouldReceive:)的替代实现可以是:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    return gestureRecognizer.view === touch.view
}

但是请注意,此替代代码不会检查touch.view是否是gestureRecognizer.view的子视图。

答案 5 :(得分:2)

使用您触摸的CGPoint的变体(SWIFT 4.0)

class MyViewController: UIViewController, UIGestureRecognizerDelegate {

  func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {

// Get the location in CGPoint
    let location = touch.location(in: nil)

// Check if location is inside the view to avoid
    if viewToAvoid.frame.contains(location) {
        return false
    }

    return true
  }
}

答案 6 :(得分:2)

清除Swift方式

x=k

答案 7 :(得分:1)

请注意,gestureRecognizer API已更改为:

gestureRecognizer(_:shouldReceive:)

特别注意第一个参数的外部标签的下划线(跳过)指示符。

使用上面提供的许多示例,我没有收到该事件。下面是一个适用于当前版本的Swift(3+)的示例。

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    var shouldReceive = false
    if let clickedView = touch.view {
        if clickedView == self.view {
            shouldReceive = true;
        }
    }
    return shouldReceive
}

答案 8 :(得分:1)

加上上述解决方案,请不要忘记查看子视图的User Interaction Enabled

enter image description here

答案 9 :(得分:0)

快捷键4:

touch.view现在是可选的,因此基于@Antoine的答案:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if let touchedView = touch.view, touchedView.isDescendant(of: deductibleBackgroundView) {
        return false
    }
    return true
}

答案 10 :(得分:0)

我必须防止在子视图上显示手势。唯一有效的方法是允许并保留第一个视图,并在所有后续视图中阻止手势:

   var gestureView: UIView? = nil

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if (gestureView == nil || gestureView == touch.view){
            gestureView = touch.view
            return true
        }
        return false
     }

答案 11 :(得分:0)

如果您不希望“双击识别器”与按钮和/或其他控件发生冲突,则可以将self设置为UIGestureRecognizerDelegate并实施:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool
{
    return !(touch.view is UIControl)
}