1

I have UIViewController with UITableView. I want to dismiss the UIViewController when user pull down the table. By adding UIPanGestureRecognizer to UIViewController's view will work only if table contents are less and table is not scrollable. So I added UIPanGestureRecognizer to tableView :

self.detailTableView.bounces = true
let gesture = UIPanGestureRecognizer(target: self, action: #selector(onPan(_:)))
gesture.delegate = self
self.detailTableView.gestureRecognizers = [gesture]

onPan Method :

@objc func onPan(_ panGesture: UIPanGestureRecognizer) {
    guard self.detailTableView.contentOffset.y <= 0 else {
        return
    }

    func slideViewVerticallyTo(_ yPoint: CGFloat) {
        self.view.frame.origin = CGPoint(x: 0, y: yPoint)
    }

    switch panGesture.state {

    case .began, .changed:
        // If pan started or is ongoing then
        // slide the view to follow the finger
        let translation = panGesture.translation(in: view)
        let yPoint = max(0, translation.y)
        slideViewVerticallyTo(yPoint)

    case .ended:
        // If pan ended, decide it we should close or reset the view
        // based on the final position and the speed of the gesture
        let translation = panGesture.translation(in: view)
        let velocity = panGesture.velocity(in: view)
        let closing = (translation.y > self.view.frame.size.height / 2) ||
            (velocity.y > minimumVelocityToHide)

        if closing {
            UIView.animate(withDuration: animationDuration, animations: {
                // If closing, animate to the bottom of the view
                slideViewVerticallyTo(self.view.frame.size.height)
            }, completion: { (isCompleted) in
                if isCompleted {
                    // Dismiss the view when it disappeared
                    // Dismiss UIViewController here....
                }
            })
        } else {
            // If not closing, reset the view to the top
            UIView.animate(withDuration: animationDuration, animations: {
                slideViewVerticallyTo(0)
            })
        }

    default:
        // If gesture state is undefined, reset the view to the top
        UIView.animate(withDuration: animationDuration, animations: {
            slideViewVerticallyTo(0)
        })
    }
}

Also implemented following delegate because as tableView bounce property is set to true, table gets bounce in all direction. By enabling only vertical direction bounce was not working.

public func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if let panRecognizer = gestureRecognizer as? UIPanGestureRecognizer {
            // Ensure it's a Vertical drag
            let velocity = panRecognizer.velocity(in: self.view)
            if abs(velocity.y) < abs(velocity.x) {
                return false
            }
        } else {
            return false
        }
        return true
    }

This code was working fine with Xcode 10.2.1. Now I have updated to Xcode 11.3, dismiss is working but it has blocked scrolling of tableView.

Can anyone provide the solution?

Thank you in advance.

Trup
  • 635
  • 5
  • 17

1 Answers1

2

You can try to handle the gesture recognizers in following methods. By doing this you can achieve the drag down to dismiss functionality once you find the view gesture attached to and the gesture kind.

extension ViewController: UIGestureRecognizerDelegate {

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {

        if gestureRecognizer.isKind(of: UIPanGestureRecognizer.self) && otherGestureRecognizer.isKind(of: UIPanGestureRecognizer.self) && gestureRecognizer.view == tableview && gestureRecognizer.view == tableview {
            // your logic here
        }
        return true
    }

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {

        if gestureRecognizer.isKind(of: UIPanGestureRecognizer.self) && otherGestureRecognizer.isKind(of: UIPanGestureRecognizer.self) && gestureRecognizer.view == tableview && gestureRecognizer.view == tableview {
            // your logic here
        }
        return true
    }

}

Nisarg Shah
  • 724
  • 5
  • 12