UITapGestureRecognizer轻按self.view而忽略子视图(UITapGestu

2019-08-19 12:57发布

我需要实现一个功能时,我加倍的self.view龙头(的观点,将调用一些代码UIViewCotroller )。 但是,我对这个观点的其他UI对象,我不希望任何识别对象附加到所有这些问题。 我发现下面如何使我的看法手势这种方法,我知道它是如何工作的。 现在我在盘口选择哪种方式对创造这个识别器忽略子视图的前面。 有任何想法吗? 谢谢。

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

Answer 1:

你应该采取UIGestureRecognizerDelegate内部协议self对象,并调用下面的方法来检查视图。 在此方法中,检查你的看法对touch.view并返回相应的布尔(是/否)。 事情是这样的:

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

编辑:请,还要检查@伊恩的回答!



Answer 2:

另一种方法是只比较如果触摸的观点是举手投足查看,因为后人将无法通过的情况。 一个好的,简单的一行:

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


Answer 3:

而对于斯威夫特变种:

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

提提, isDescendantOfView返回一个Boolean值,它指示接收器是否是到该视图的给定视图的或相同的子视图。



Answer 4:

完整的迅速解决(委托必须实现,并且识别(一个或多个)设置):

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


Answer 5:

随着iOS的11和雨燕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



Answer 6:

变体使用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
  }
}


Answer 7:

清除斯威夫特方式

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


Answer 8:

需要注意的是gestureRecognizer API已更改为:

gestureRecognizer(_:shouldReceive :)

要特别注意,第一个参数的外部标签下划线(跳跃)指标。

使用许多的上面提供的示例,我没有接收到该事件。 下面是一个对于斯威夫特(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
}


Answer 9:

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



Answer 10:

斯威夫特4:

touch.view现在是可选的,因此基于@安东尼的回答:

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


Answer 11:

我不得不防止孩子视图的姿态。 只有工作的事情是让并保持第一视图和防止全部的未来看法的姿态:

   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
     }


文章来源: UITapGestureRecognizer tap on self.view but ignore subviews