adit
adit

Reputation: 33644

UISwipeGestureRecognizer and UIPanGestureRecognizer in one view issues

I have the following code:

    UISwipeGestureRecognizer *swipeGestureRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeHighlightReadingVC:)];
    swipeGestureRecognizer.delegate = self;
    [self.highlightReadingVC_.view addGestureRecognizer:swipeGestureRecognizer];

    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panHighlightReadingVC:)];
    panGestureRecognizer.delegate = self;
    [panGestureRecognizer requireGestureRecognizerToFail:swipeGestureRecognizer];
    [self.highlightReadingVC_.view addGestureRecognizer:panGestureRecognizer];

My issue is that although I am swiping on the view, it always detects the pan gesture first. I want the swipe to be recognized first before the pan/drag. How do I do that?

Upvotes: 2

Views: 2222

Answers (2)

user246672
user246672

Reputation:

If the goal is to have pan gesture/s prevent recognition of swiping (the usual case):

swipeGesture.requireGestureRecognizerToFail(panGesture)

If the goal is to have swipe gesture/s prevent recognition of panning (the unusual case):

panGesture.requireGestureRecognizerToFail(swipeGesture)

Also do the usual:

panGesture.delegate = self
swipeGesture.delegate = self

And implement shouldRecognizeSimultaneouslyWithGestureRecognizer to always return true

Note: on things like UIWebView's and UIScrollView's to correctly interpret a single-touch swipe, it's best to requireGestureRecognizerToFail all three (3) of: a pan, a long press and a second swipe recognizer with .numberOfTouchesRequired = 2 for the UX to work intuitively.

Here's what we use (Swift):

class AboutViewController: UIViewController, UIGestureRecognizerDelegate {

    @IBOutlet var webView: UIWebView!

    var swipeToDismiss: UISwipeGestureRecognizer {
        var r = UISwipeGestureRecognizer(target: self, action: "dismiss:")
        r.direction = .Right
        r.delegate = self
        r.requireGestureRecognizerToFail(longPress)
        r.requireGestureRecognizerToFail(pan)
        r.requireGestureRecognizerToFail(doubleSwipe)
        return r
    }

    var doubleSwipe: UISwipeGestureRecognizer {
        var r = UISwipeGestureRecognizer()
        r.direction = .Right
        r.delegate = self
        r.numberOfTouchesRequired = 2
        return r
    }

    var longPress: UILongPressGestureRecognizer {
        var r = UILongPressGestureRecognizer()
        r.allowableMovement = 4000.0
        r.delegate = self
        return r
    }

    var pan: UIPanGestureRecognizer {
        var r = UIPanGestureRecognizer()
        r.delegate = self
        return r
    }

    func dismiss(recognizer: UISwipeGestureRecognizer!) {
         // ...popViewControllerAnimated(true)
    }

    private func setupWebView() {
        // ...
        webView.addGestureRecognizer(longPress)
        webView.addGestureRecognizer(swipeToDismiss)
        webView.addGestureRecognizer(pan)
        webView.addGestureRecognizer(doubleSwipe)
    }


    // MARK: - UIGestureRecognizerDelegate

    func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
        println("gesture start: \(gestureRecognizer)")
        return true
    }

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        println("multiple gestures: \(gestureRecognizer), \(otherGestureRecognizer)")
        return true
    }


    // MARK: - UIViewController

    override func viewDidLoad() {
        super.viewDidLoad()

        setupWebView()
    }
}

Upvotes: 0

Girish
Girish

Reputation: 4712

You're going to want to set one of the two UIGestureRecognizer's delegates to an object that makes sense (likely self) then listen, and return YES.

- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}

This method is called when recognition of a gesture by either gestureRecognizer or otherGestureRecognizer would block the other gesture recognizer from recognizing its gesture. Note that returning YES is guaranteed to allow simultaneous recognition; returning NO, on the other hand, is not guaranteed to prevent simultaneous recognition because the other gesture recognizer's delegate may return YES.

I also faced same issue in my app & it works fine for me. So it may solve your problem.

Upvotes: 2

Related Questions