PROBLEM:
When the UIPanGestureRecognizer
is underlying a UIScrollView
(which unfortunately does also effect UIPageViewController
) the maximumNumberOfTouches
is not behaving as expected - the minimumNumberOfTouches
however always limits the lower end correctly.
When monitoring these parameters they seem to do their job - it's just that UIScrollView
doesn't honor them and ignores their values!
REMEDY:
You can find the solution in my answer to:
UIScrollView scrolling only with one finger
BTW:
The difference you experience between one
finger and two
finger panning is because with one finger you are using the panGestureRecognizer
. With two fingers the pinchGestureRecognizer
(which can also pan at the same time) kicks in and you have no deceleration phase and the view stops panning and zooming immediately after releasing your fingers. Deactivate the pinchGestureRecognizer
and you will see that the panGestureRecognizer
takes over - even for two fingers - and panning is smooth again... ;-)
SIMULTANEOUSLY - et voilà...
Delegate callbacks for a perfect simultaneous 2 finger scrolling
and zooming
behavior:
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
self.pinchGestureRecognizer.enabled = NO;
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
self.pinchGestureRecognizer.enabled = NO;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
self.pinchGestureRecognizer.enabled = YES;
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
self.pinchGestureRecognizer.enabled = YES;
}
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
self.panGestureRecognizer.enabled = NO;
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
self.panGestureRecognizer.enabled = YES;
}
Fast pinch
starts zooming!
Fast pan
starts panning!
Stopping a decelerating pan with two new fingers down on the screen and start dragging again does not let the clumsy pinchGestureRecognizer take over (default) but rather smoothly go into the next pan/deceleration phase - like with one finger!
FOR PERFECTIONISTS:
Put 2 fingers on the screen and - DON'T MOVE NOW - If you don't start pinching within the first 0.5 seconds zooming
gets locked and only panning
is available:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
if ([gestureRecognizer.view isMemberOfClass:[MY_CustomScrollView class]]) {
NSLog(@"IN SCROLL-VIEW...");
if (gestureRecognizer == self.pinchGestureRecognizer) {
if (_pinchGestureLocked) {
NSLog(@"...but TOO late for zooming...");
return NO;
} else {
NSLog(@"...ZOOMING + PANNING...");
return YES;
}
} else if (gestureRecognizer == self.panGestureRecognizer){
if (gestureRecognizer.numberOfTouches > 2) {
NSLog(@"...but TOO many touches for PANNING ONLY...");
return NO;
} else {
NSLog(@"...PANNING...");
return YES;
}
} else {
NSLog(@"...NO PAN or PINCH...");
return YES;
}
} else {
NSLog(@"NOT IN SCROLL-VIEW...");
}
return YES;
}
BOOL _pinchGestureLocked = NO;
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
_pinchGestureLocked = YES;
}
- (void) touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
_pinchGestureLocked = NO;
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
_pinchGestureLocked = NO;
}
Happy gesture-recognizing!
NSLog(@"%@", [pagingScrollView valueForKeyPath:@"gestureRecognizers.class"]);
->( UIScrollViewDelayedTouchesBeganGestureRecognizer, UIScrollViewPanGestureRecognizer, UIScrollViewPagingSwipeGestureRecognizer )
. I think you'll need to pick a different UI. – Amandine