views:

2213

answers:

2

I have a UIScrollView that's around 600pixels 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?

A: 

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.

Tyler
Tyler,Thanks for the response. I can detect horizontal "swipes" but only if they have very very little change in Y. If I moved more than +-5 pixels roughly on the y-axis it seems the ScrollView takes over and starts scrolling vertically. This isn't that realistic as it takes me a few tries (on the device) to get a swipe with this little change on the Y-axis. Did you experience similar behavior?
tuzzolotron
A: 

If @Tyler's method doesn't work, try putting a view right over the UIScrollView, and handle any horizontal swipes in that view's touchesBegan, and pass vertical ones to the next responder. You can be a little fuzzy and handle anything that has more of a horizontal movement than vertical as a horizontal swipe, and pass the more pure vertical swipes to the UISCrollView (via nextResponder).

mahboudz
I tried this but wasn't able to get any touches in the view...
tuzzolotron
The new view is the one not getting any touches? Is it a child of the scrollview, or a sibling, above it? Is it set to accept user interaction?
mahboudz