views:

1790

answers:

2

I have a subclass of UIScrollView that overrides

touchesBegan:withEvent: touchesMoved:withEvent:
touchesEnded:withEvent:

Overriding these three seems to be a technique that is widely used (based on my observations in forums). However, as soon as I compiled this code on OS3, these methods are no longer being called. Has anyone else seen this problem? Is there a known fix that doesn't use undocumented methods?

My first attempt at a solution was to move all the touchesBegan/Moved/Ended methods down into my content view and set

delaysContentTouches = NO; canCancelContentTouches = NO;

This worked partially, but left me unable to pan when I have zoomed. My second attempt only set canCancelContentTouches = NO when there were two touches (thus passing the pinch gesture through to the content). This method was sketchy and didn't work very well.

Any ideas? My requirement is that the scroll view must handle the pan touches, and I must handle the zoom touches.

A: 

Check out http://stackoverflow.com/questions/877828/uiscrollview-touches-vs-subview-touches looks like it might be the same issue.

Steve918
Thanks for the tip, but to me it looks like that's not the same problem. That problem has to do with ignoring events if you're already handling them in a subview. My problem is about how to expediently forward a 2-touchCount "pinch" event from a scroll view down to its subview while treating all other touches as pan events.
zaccox
A: 

My solution is not pretty. Basically there is a scroll view who contains a content view. The scroll view does not implement touchesBegan,Moved,Ended at all. The content view maintains a pointer to his parent (called "parentScrollView" in this example). The content view handles the logic and uses [parentScrollView setCanCancelContentTouches:...] to determine whether or not to let the parent view cancel a touch event (and thus perform a scroll event). The tap count logic is there because users rarely place both fingers onscreen at exactly the same time so the first touch must be ignored if it is very quickly followed by a second.

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event
{
    if(parentViewIsUIScrollView)
    {
     UIScrollView * parentScrollView = (UIScrollView*)self.superview;
     if([touches count] == 1)
     {
      if([[touches anyObject] tapCount] == 1)
      { 
       if(numberOfTouches > 0)
       {
        [parentScrollView setCanCancelContentTouches:NO];
        //NSLog(@"cancel NO - touchesBegan - second touch");
        numberOfTouches = 2;
       }
       else
       {
        [parentScrollView setCanCancelContentTouches:YES];
        //NSLog(@"cancel YES - touchesBegan - first touch");
        numberOfTouches = 1;
       } 
      }
      else
      {
       numberOfTouches = 1;
       [parentScrollView setCanCancelContentTouches:NO];
       //NSLog(@"cancel NO - touchesBegan - doubletap");
      }
     }
     else
     {  
      [parentScrollView setCanCancelContentTouches:NO];
      //NSLog(@"cancel NO - touchesBegan");
      numberOfTouches = 2;
     }
     //NSLog(@"numberOfTouches_touchesBegan = %i",numberOfTouches);
    }
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{   
    if(touchesCrossed)
     return;

    if(parentViewIsUIScrollView)
    {
     UIScrollView * parentScrollView = (UIScrollView*)self.superview;
     NSArray * thoseTouches = [[event touchesForView:self] allObjects]; 

     if([thoseTouches count] != 2)
      return;
     numberOfTouches = 2;


     /* compute and perform pinch event */

     [self setNeedsDisplay];
     [parentScrollView setContentSize:self.frame.size];
    }
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{   
    touchesCrossed = NO;
    if(parentViewIsUIScrollView)
    {
     numberOfTouches = MAX(numberOfTouches-[touches count],0);
     [(UIScrollView*)self.superview setCanCancelContentTouches:YES];
     //NSLog(@"cancel YES - touchesEnded");
     //NSLog(@"numberOfTouches_touchesEnded = %i",numberOfTouches); 
    }
}
zaccox
This is brilliant! A very elegant way to handle the situation.
Nick Farina