The test case is easily reproduced: download Apple's PhotoScroller sample app, and try to adapt it so that panning (both around a zoomed image, and between each image) only works with two fingers.
Setting the panGestureRecognizer
for both the pagingScrollView
and the imageScrollView
to only accept a min & max of 2 touches seems like a good place to start, however it doesn't work. It lets you scroll around an image with two fingers just fine*, however paging then doesn't work.
I've tried so many combinations of settings and custom gesture recognizers, and I'm a bit stumped. Is a custom scroll view subclass going to be of any use, or can I somehow manipulate the scroll view delegate methods to make it work?
*EDIT: Actually, it doesn't scroll fine in this situation. The view no longer glides smoothly as with a single touch...
UPDATE: I'm still struggling with this one. I would appreciate some input from somebody who has played around with UIGestureRecognizer
s and UIScrollView
s.
EDIT:
Setting the ImageScrollView
class to only accept two touches:
- (id)initWithFrame:(CGRect)frame
{
// ...
// Template code
// ...
[self.panGestureRecognizer setMinimumNumberOfTouches:2];
[self.panGestureRecognizer setMaximumNumberOfTouches:2];
}
Setting PhotoViewController
's pagingScrollView
to only accept two touches:
- (void)loadView
{
// ...
// Template code
// ...
[pagingScrollView.panGestureRecognizer setMinimumNumberOfTouches:2];
[pagingScrollView.panGestureRecognizer setMaximumNumberOfTouches:2];
}
These modifications are made directly on top of the PhotoScroller sample app. I would expect these simple changes to work for two-finger interaction, however the side-effects are odd (as explained above).
It would appear that this is either impossible, or very very difficult (i.e. roll your own scroll view from scratch). I used an Apple Tech support incident and they were unable to help. If a solution becomes available I'll happily mark it as the accepted answer!
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With