Debugging gesture recognizers
Recently I was trying to figure out why pan gestures weren’t being picked up. The case I was dealing with was a collection view that did not respond to swipe gestures near the edges of the screen.
After consulting with a colleague and looking up some documentation based on his advice, I found the conflict was partially due to the interativePopGestureRecognizer
that lives within the UINavigationController
. For background, this gesture recogniser was introduced in iOS 7 to allow swiping back to previous view controllers in the navigation controller’s stack.
Disabling it helped solve some of the conflicts.
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
But doing a quick google would have told you that, the reason for this post is another trick I picked up along the way. I wanted to see if there was a way to get a list of gesture recognizers that were conflicting.
The way to do that is to register as a delegate to any of the gesture recognizers that are part of the conflict and implement the following method.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
NSLog(@"Gesture Recognizer 1 = %@", gestureRecognizer);
NSLog(@"Gesture Recognizer 2 = %@", otherGestureRecognizer);
return YES;
}
This method will let you know exactly which gesture recognizers are being activated. One challenge with this was that the only gesture recognizer I knew about was the pan gesture recognizer on the collection view, but unfortunately attempting re-assign the pan gesture recognizer on a collection view will result with an assertion failure
***
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'UIScrollView's built-in pan gesture recognizer must have its scroll view as its delegate.'
***
The way I got this to work without too much hackery was to simply add another gesture recognizer to the edges - UIScreenEdgePanGestureRecognizer
was perfect for this.
UIScreenEdgePanGestureRecognizer *gr = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(didSwipe:)];
gr.delegate = self;
gr.edges = UIRectEdgeLeft | UIRectEdgeRight;
[self.view addGestureRecognizer:gr];
2014-12-29 17:08:27.707 TestProject[1678:34518] Gesture Recognizer 1 = UIScreenEdgePanGestureRecognizer: 0x7f9789d7fae0; state = Failed; delaysTouchesBegan = YES; view = UIView 0x7f9789cbb5f0; target= (action=didSwipe:, target=TestViewController 0x7f9789d96c50)
2014-12-29 17:08:27.707 TestProject[1678:34518] Gesture Recognizer 2 = UIPanGestureRecognizer: 0x7f9789c8e610; state = Began; view = UILayoutContainerView 0x7f9789c7c0c0; target= (action=_swipe:, target=UIPopoverController 0x7f9789c8b8d0)
And there you have it, a quick way to check out which gesture recognisers are causing you grief!