Search code examples
swiftuitapgesturerecognizer

Swift - UITapGestureRecognizer for parent view only


I have a UIViewController with a subview of a UIView. I add a UITapGestureRecognizer to the UIViewController to dismiss the view, but when I tap on the subview, the whole view still dismisses and I only want to dismiss when tapping the parent view.

var backgroundView = UIView()

override func viewDidLoad() {
    super.viewDidLoad()
    view.backgroundColor = .clear
    let tap = UITapGestureRecognizer(target: self, action: #selector(didTapOutsideBackgroundView))
    tap.numberOfTapsRequired = 1
    view.addGestureRecognizer(tap)
    setupUI()
}

func setupUI() {
    
    view.addSubview(backgroundView)
    backgroundView.translatesAutoresizingMaskIntoConstraints = false
    backgroundView.layer.cornerRadius = 8
    NSLayoutConstraint.activate([
        backgroundView.topAnchor.constraint(equalTo: view.topAnchor, constant: distanceFromTop ?? 0),
        backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
        backgroundView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
    ])
    backgroundView.backgroundColor = .systemBackground
    // add subviews to backgroundView
    backgroundView.addSubview(pageTitle)
    backgroundView.addSubview(closeButton)
    backgroundView.addSubview(itemLabel)
    backgroundView.addSubview(itemNameLabel)
    backgroundView.addSubview(priceLabel)
    backgroundView.addSubview(quantityLabel)
    backgroundView.addSubview(itemQuantityLabel)
    backgroundView.addSubview(itemOriginalPriceLabel)
}

@objc func didTapOutsideBackgroundView(sender: UITapGestureRecognizer) {
    print("called")
    dismiss(animated: true)
}

Solution

  • You can find tapped view and ignore the tap if its a backgroundView with this in your didTapOutsideBackgroundView

    @objc func didTapOutsideBackgroundView(sender: UITapGestureRecognizer) {
    
        let location = sender.location(in: self.view)
        if let view = self.view.hitTest(location, with: nil), let guester = view.gestureRecognizers {
            if guester.contains(sender) {
                print("Parent tapped")
                dismiss(animated: true)
            }
        } else {
            print("Ignore tap")
        }
    }