Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conflict between ScrollView pan gesture and panGestureRecognizer

I have a UIScrollView in a UIViewController, which is showed modally by a segue, and an additional UIPanGestureRecognizer do dismiss the view controller by pan. This gesture only works if

 scrollView.contentOffset.y == 0

The problem is, now two pan gestures conflict with each other, and I can't scroll the view any more.

To solve this I have tried to use gestureRecognizer(_: shouldRecognizeSimultaneouslyWith:) method, returning yes, and also, I've tried to add my custom pan gesture to UIScrollView pan gesture recognizer like this:

 scrollView.panGestureRecognizer.addTarget(self, action: #selector(handlePanGesture(_:)))

But these don't solve the problem If you know how to solve this issue, I would appreciate your help.

EDITED

Here is the code for my pan gesture that dismisses the view controller:

     @IBAction func handlePanGesture(_ sender: UIPanGestureRecognizer) {
    let percentThreshold: CGFloat = 0.3

    if scrollView.contentOffset.y == 0 {
        let translation = sender.translation(in: view)
        let verticalMovement = translation.y / view.bounds.height
        let downwardMovement = fmaxf(Float(verticalMovement), 0.0)
        let downwardMovementPercent = fminf(downwardMovement, 1.0)
        let progress = CGFloat(downwardMovementPercent)

        guard let interactor = interactor else {return}
        switch sender.state {
        case .began:
            interactor.hasStarted = true
            dismiss(animated: true, completion: nil)
        case .changed:
            interactor.shouldFinish = progress > percentThreshold
            interactor.update(progress)
        case .cancelled:
            interactor.hasStarted = false
            interactor.cancel()
        case .ended:
            interactor.hasStarted = false
            interactor.shouldFinish ? interactor.finish() : interactor.cancel()
        default:
            break
        }

    }
}

EDITED_2 Here is the code for Interactor:

class Interactor: UIPercentDrivenInteractiveTransition {
var hasStarted = false
var shouldFinish = false 

}

P.s. I know that there is a bunch of similar questions but they don't work for me.

like image 555
Tigran Iskandaryan Avatar asked Feb 04 '23 02:02

Tigran Iskandaryan


2 Answers

To allow scrolling when a UIPanGestureRecognizer is on a ScrollView you need to create a UIGestureRecognizerDelegate that returns true on gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:)

If you don't do this, scrolling will not be possible on the ScrollView.

This is done like so:

let scrollViewPanGesture = UIPanGestureRecognizer(target: self, action: #selector(onPan(_:)))
scrollViewPanGesture.delegate = self
scrollView.addGestureRecognizer(scrollViewPanGesture)

extension ViewController: UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}
like image 94
bnussey Avatar answered Feb 11 '23 00:02

bnussey


I'm not sure but you can try adding the ViewController as a UIPanGestureRecognizer delegate of the swipe to dismiss pan gesture and implementing gestureRecognizerShouldBegin(_:);

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    return scrollView.contentOffset.y == 0
}

So the gesture to dismiss will start only if the content offset is zero.

like image 31
Rico Crescenzio Avatar answered Feb 10 '23 22:02

Rico Crescenzio