Archive
Solution: UIScrollview that doesn’t interfere with content touches
Hi there, i’m currently working on a drawing-application which uses a scrollview to navigate threw the content. With the normal UIScrollview you will definitely run into problems!
The problem is that UIScrollView will only deliver taps but no movement gestures to it’s content.
1) So i was looking for a solution to pan and zoom with 2 fingers and interact with the content-view with one finger.
2) Also it should be possible to have a period of time in which the 1 finger touch event can be canceled by the two finger events. This is useful since people tend to start with one finger followed by the second one a little later.
3)Also it should be possible to touch the screen with a second finger without canceling the content interaction!
The idea was to filter all the touch-events, but since UIScrollView uses gesture recognizers (namely UIScrollViewPanGestureRecognizer which inherits from UIPanGestureRecognizer) you can’t filter these touches since there aren’t any but the first touchesBegan…
To solve these problems i did the following:
- Set setCanCancelContentTouches:NO when you detect a 1 touch event in touchesBegan: works but you still have the problem with 2).
- Solution: Use a timer to set setCanCancelContentTouches:NO after a period like 0.1 seconds or so
- Problem: In the first moments the gesture recognizer will interfere with your touch movements and use them instead
- Solution: Reconfigure all pangesture recognizers to only accept 2 touch events
- Problem: In the first moments the gesture recognizer will interfere with your touch movements and use them instead
- Solution: Use a timer to set setCanCancelContentTouches:NO after a period like 0.1 seconds or so
-
#import “JWTwoFingerScrollView.h”
-
@implementation JWTwoFingerScrollView
-
#pragma mark -
-
#pragma mark Event Passing
-
- (id)initWithCoder:(NSCoder *)coder {
-
self = [super initWithCoder:coder];
-
if (self) {
-
for (UIGestureRecognizer* r in self.gestureRecognizers) {
-
NSLog(@“%@”,[r class]);
-
if ([r isKindOfClass:[UIPanGestureRecognizer class]]) {
-
[((UIPanGestureRecognizer*)r) setMaximumNumberOfTouches:2];
-
[((UIPanGestureRecognizer*)r) setMinimumNumberOfTouches:2];
-
}
-
}
-
}
-
return self;
-
}
-
-(void)firstTouchTimerFired:(NSTimer*)timer {
-
[self setCanCancelContentTouches:NO];
-
}
-
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
-
[self setCanCancelContentTouches:YES];
-
touchesBeganTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(firstTouchTimerFired:) userInfo:nil repeats:NO];
-
[touchesBeganTimer retain];
-
[touchFilter touchesBegan:touches withEvent:event];
-
}
-
}
-
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
-
[touchFilter touchesMoved:touches withEvent:event];
-
}
-
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
-
[touchFilter touchesEnded:touches withEvent:event];
-
}
-
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
-
[touchFilter touchesCancelled:touches withEvent:event];
-
}
-
@end
It really took me ages to get this running, there were plenty other solutions which all didnt meet my needs. Some used a timer but delayed the first touch event, others allowed only one touch event but interrupted as soon as there was a two finger touch event. Some threads on stackoverflow might be interesting for you, since it also helped me to get this solution working!
http://stackoverflow.com/questions/787212/scrolling-with-two-fingers-with-a-uiscrollview
if you want, download the files!