Archive

Posts Tagged ‘Scrolling’

Solution: UIScrollview that doesn’t interfere with content touches

December 14, 2011 3 comments

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:

  1. 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
Note that i check the gesture recognizers against isKindOfClass not isMemberOfClass since UIScrollViewPanGestureRecognizer inherits from UIPanGestureRecognizer.
Also dont worry about touchFilter! This is the contentview, which in fact doesn’t filter the touches but uses the prefiltered ones!
When the user starts with a one finger gesture and (before timer fired) continues with a second one, beganTouches: and canceledTouches: will be called in this order. The number of touches in canceledTouches will therefore be 2; your contentview must be aware of this, cause if it ignores two touch events it won’t get the canceled event which could result in quite strange behavior.
  1. #import “JWTwoFingerScrollView.h”
  2. @implementation JWTwoFingerScrollView
  3. #pragma mark -
  4. #pragma mark Event Passing
  5. - (id)initWithCoder:(NSCoder *)coder {
  6. self = [super initWithCoder:coder];
  7. if (self) {
  8. for (UIGestureRecognizer* r in self.gestureRecognizers) {
  9. NSLog(@“%@”,[r class]);
  10. if ([r isKindOfClass:[UIPanGestureRecognizer class]]) {
  11. [((UIPanGestureRecognizer*)r) setMaximumNumberOfTouches:2];
  12. [((UIPanGestureRecognizer*)r) setMinimumNumberOfTouches:2];
  13. }
  14. }
  15. }
  16. return self;
  17. }
  18. -(void)firstTouchTimerFired:(NSTimer*)timer {
  19. [self setCanCancelContentTouches:NO];
  20. }
  21. - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
  22. [self setCanCancelContentTouches:YES];
  23. if ([event allTouches].count == 1){
  24. touchesBeganTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(firstTouchTimerFired:) userInfo:nil repeats:NO];
  25. [touchesBeganTimer retain];
  26. [touchFilter touchesBegan:touches withEvent:event];
  27. }
  28. }
  29. - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
  30. [touchFilter touchesMoved:touches withEvent:event];
  31. }
  32. - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
  33. NSLog(@“ended %i”,[event allTouches].count);
  34. [touchFilter touchesEnded:touches withEvent:event];
  35. }
  36. -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
  37. NSLog(@“canceled %i”,[event allTouches].count);
  38. [touchFilter touchesCancelled:touches withEvent:event];
  39. }

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!

Follow

Get every new post delivered to your Inbox.