Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting horizontal swipes in a UIScrollView with a vertical scroll

I have a UIScrollView that's around 600 pixels in height and 320 in width. So I'm allowing the user to scroll vertically.

I'm also trying to capture horizontal swipes on the view. The problem seems to be that when a user swipes horizontally with some accidental vertical movement, the UIScrollView scrolls and my touchesEnded delegate method never gets called.

Here's my code:

- (void)touchesEnded: (NSSet *)touches withEvent: (UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint currentPosition = [touch locationInView:self];

    if (currentPosition.x + 35 < gestureStartPoint.x)
    {  
        NSLog(@"Right");
    }    
    else if (currentPosition.x - 35 > gestureStartPoint.x)
    {
        NSLog(@"Left");
    }    
    else if (!self.dragging)
    {
        [self.nextResponder touchesEnded: touches withEvent:event]; 
    }

    [super touchesEnded: touches withEvent: event];
}

Does anyone know how I can get this to work even when there is vertical drag involved?

like image 208
tuzzolotron Avatar asked Sep 24 '09 16:09

tuzzolotron


1 Answers

UIScrollView tries to figure out which touches to pass through to its contents, and which are scrolls, based on movement immediately after a touch begins. Basically, if the touch appears to be a scroll right away, it handles that gesture and the contents never see it; otherwise, the gesture gets passed through (with a very short delay for the first touch).

In my experience, I've been able to capture horizontal swipes in the contents of a UIScrollView that handled vertical-only scrolling -- it basically just worked by default for me. I did this by setting the contentSize to be the same as the width of the scroll view's frame, which is enough information to tell the UIScrollView that it won't be handling horizontal scrolling.

It sounds like you're having trouble with the default behavior, though. One hardware gotcha is that it's very hard to simulate a finger swipe on a laptop's trackpad. If I were you, I would test out the default UIScrollView setup using either a mouse or, preferably, on the device itself. I found that these input methods work much better for conveying swipes.

If that doesn't work, here is a very pertinent paragraph from Apple's UIScrollView docs:

Because a scroll view has no scroll bars, it must know whether a touch signals an intent to scroll versus an intent to track a subview in the content. To make this determination, it temporarily intercepts a touch-down event by starting a timer and, before the timer fires, seeing if the touching finger makes any movement. If the time fires without a significant change in position, the scroll view sends tracking events to the touched subview of the content view. If the user then drags their finger far enough before the timer elapses, the scroll view cancels any tracking in the subview and performs the scrolling itself. Subclasses can override the touchesShouldBegin:withEvent:inContentView:, pagingEnabled, and touchesShouldCancelInContentView: methods (which are called by the scroll view) to affect how the scroll view handles scrolling gestures.

In summary, you could try what they suggest by subclassing UIScrollView and overriding the suggested methods.

like image 66
Tyler Avatar answered Sep 29 '22 10:09

Tyler