0

I have a PanGestureRecognizer set on a child view controller's container view. This is essentially a drawer view, so I want the child view controller to handle any scrolls, except for when the child view controller's table view is scrolled to the top and the user pans down. In this case, I want the container view gesture recogniser to take over so the child view controller as a whole can be animated down. I have a delegate for the gesture recogniser and this works perfectly if, instead of a child view controller and container view, it is just a table view and I add the pan gesture recogniser to that. The way it is now though, the delegate is returning true when it should be, yet the handlePan method is not being called? Any ideas would be appreciated. Thanks!

All of the below code is in the parent UIViewController that has a container view, which I am applying the gesture recogniser to. Everything displays correctly, just the gesture recogniser method is not called, but the delegate is.

func setUpItemDetailsController() {
        guard let itemDetailsController = itemDetailsController else { return }
        add(itemDetailsController)
        itemDetailsContainerView.addSubview(itemDetailsController.view)

        let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
        panGestureRecognizer.delegate = self
        itemDetailsContainerView.addGestureRecognizer(panGestureRecognizer)
    }

@objc func handlePan(_ sender: UIPanGestureRecognizer) {
     ...
}

extension MoverScanAndDiscoverResultController: UIGestureRecognizerDelegate {
    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        guard let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer else { return true }

        let translation = panGestureRecognizer.translation(in: view).y
        let topLimit = view.bounds.height - self.statusAndNavBarCombinedHeight

        print(itemDetailsTableView.contentOffset.y)

        // Allows for normal UITableView scrolling
        if translation < 0
            && resultCardViewBottomConstraint.constant == topLimit
            || itemDetailsController?.tableView.contentOffset.y ?? 0 > 0 {
            return false
        }

        return true
    }
}
Bhavesh Nayi
  • 3,626
  • 1
  • 27
  • 42
Michael
  • 1,084
  • 13
  • 18
  • If the delegate method `gestureRecognizerShouldBegin` is called and returns `false`, then the action method `handlePan` will never be called. Well, maybe it _is_ returning `false`. – matt Apr 24 '19 at 04:05
  • it returns true and still does not get called – Michael Apr 24 '19 at 04:10
  • I'm guessing that the gesture is being "eaten" by the table view. – matt Apr 24 '19 at 04:13
  • yeah it must be being taken somewhere, but not sure how the function isn't called if that is the only function attached to the recognizer? if I do the same exact thing with just a tableview, instead of a containerview everything works – Michael Apr 24 '19 at 04:16
  • 1
    Well, what I'm guessing is the table view also has a gesture recognizer, and it wins. It eats the touch. I don't think this has anything to do with your "container view"; you can never detect a pan gesture through a table view, because the table view detects it first. – matt Apr 24 '19 at 04:19
  • not sure I follow what you mean that it can never be detected? if I apply the gesture recognizer to the tableview itself, it does not eat it – Michael Apr 24 '19 at 04:20
  • Test our hypothesis. Try disabling the table view entirely. Does your gesture work then? – matt Apr 24 '19 at 04:22
  • deleting the table view does fix the issue yes, so any suggestions on how to get it to work with the table view in? – Michael Apr 24 '19 at 04:30

1 Answers1

0

Have you tried the UIGestureRecognizerDelegate function for recognizing simultaneously with other gesture recognizers?

class MyViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        // etc...

        let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panned(_:)))
        panGestureRecognizer.delegate = self
        self.tableView.addGestureRecognizer(panGestureRecognizer)
    }

    @objc
    func panned(_ sender: UIPanGestureRecognizer) {
        print("Panning")
    }
}

extension MyViewController: UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true // obviously this could be more refined if you have other gesture recognizers
    }
}

I've not tried adding the gesture recognizer to the container view, but adding it directly to the tableView works fine for me.

SomaMan
  • 4,127
  • 1
  • 34
  • 45