PDA

View Full Version : Detecting horizontal swipe in a UITableView




lutius
Jul 28, 2008, 08:22 AM
Hi,

I have the following setup:

A UITableView which list summary information about items.
When you select an item, you switch to another UITableView, which contains Detail Information about the selected item. The detail information is presented as a List too (UITableView).

Now, say I select item No. 3 in the summary list, i'll switch to the detail view and show detail information about that No. 3 item.

What I'd like now in this Detail UITableView is to be able to:

a) use normal vertical scrolling (just normal behaviour of a UITableView)
b) Here's the tricky part: detect horizontal scrolling (swipes) within the UITableView to switch to the previous/next item Detail, eg. right-swipe = show Item No. 2 Detail, left swipe = show No. 4 Detail.

I have written a custom UITableView and implemented


#define HORIZ_SWIPE_DRAG_MIN 12
#define VERT_SWIPE_DRAG_MAX 4

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
startTouchPosition = [touch locationInView:self];
}

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

// If the swipe tracks correctly.
if (fabsf(startTouchPosition.x - currentTouchPosition.x) >= HORIZ_SWIPE_DRAG_MIN &&
fabsf(startTouchPosition.y - currentTouchPosition.y) <= VERT_SWIPE_DRAG_MAX)
{
// It appears to be a swipe.
if (startTouchPosition.x < currentTouchPosition.x)
[self myProcessRightSwipe:touches withEvent:event];
else
[self myProcessLeftSwipe:touches withEvent:event];
}
else
{
// default handling
[super touchesMoved:touches withEvent:event];
}
}




Now, this implementation seemed to work at first, but the problem is that when i do a vertical scroll to the bottom of the table, everything is fine, but as soon as i retouch the display, say to scroll up a bit, it jumps back to the top of the table.

Any idea ?



lutius
Jul 28, 2008, 03:41 PM
Never mind, I ended up with this, which apparently works well.
-------------

#define HORIZ_SWIPE_DRAG_MIN 100

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

UITouch *touch = [touches anyObject];
CGPoint newTouchPosition = [touch locationInView:self];
if(mystartTouchPosition.x != newTouchPosition.x || mystartTouchPosition.y != newTouchPosition.y) {
isProcessingListMove = NO;
}
mystartTouchPosition = [touch locationInView:self];
[super touchesBegan:touches withEvent:event];
}

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

// If the swipe tracks correctly.
double diffx = mystartTouchPosition.x - currentTouchPosition.x + 0.1; // adding 0.1 to avoid division by zero
double diffy = mystartTouchPosition.y - currentTouchPosition.y + 0.1; // adding 0.1 to avoid division by zero

if(abs(diffx / diffy) > 1 && abs(diffx) > HORIZ_SWIPE_DRAG_MIN)
{
// It appears to be a swipe.
if(isProcessingListMove) {
// ignore move, we're currently processing the swipe
return;
}

if (mystartTouchPosition.x < currentTouchPosition.x) {
isProcessingListMove = YES;
[detailController moveToPreviousItem];
return;
}
else {
isProcessingListMove = YES;
[detailController moveToNextItem];
return;
}
}
else if(abs(diffy / diffx) > 1)
{
isProcessingListMove = YES;
[super touchesMoved:touches withEvent:event];
}
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
isProcessingListMove = NO;
[super touchesEnded:touches withEvent:event];
}

4GivenSoftware
Oct 31, 2009, 01:43 PM
Never mind, I ended up with this, which apparently works well.
-------------

#define HORIZ_SWIPE_DRAG_MIN 100

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
.....................

Lutius You are the Man! Thank you! I had to change it a little

#define HORIZ_SWIPE_DRAG_MIN 100
CGPoint mystartTouchPosition;
BOOL isProcessingListMove;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint newTouchPosition = [touch locationInView:self.view];
if(mystartTouchPosition.x != newTouchPosition.x || mystartTouchPosition.y != newTouchPosition.y) {
isProcessingListMove = NO;
}
mystartTouchPosition = [touch locationInView:self.view];
[super touchesBegan:touches withEvent:event];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
CGPoint currentTouchPosition = [touch locationInView:self.view];

// If the swipe tracks correctly.
double diffx = mystartTouchPosition.x - currentTouchPosition.x + 0.1; // adding 0.1 to avoid division by zero
double diffy = mystartTouchPosition.y - currentTouchPosition.y + 0.1; // adding 0.1 to avoid division by zero

if(abs(diffx / diffy) > 1 && abs(diffx) > HORIZ_SWIPE_DRAG_MIN)
{
// It appears to be a swipe.
if(isProcessingListMove) {
// ignore move, we're currently processing the swipe
return;
}

if (mystartTouchPosition.x < currentTouchPosition.x) {
isProcessingListMove = YES;
[self moveToPreviousItem];
return;
}
else {
isProcessingListMove = YES;
[self moveToNextItem];
return;
}
}
else if(abs(diffy / diffx) > 1)
{
isProcessingListMove = YES;
[super touchesMoved:touches withEvent:event];
}
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
isProcessingListMove = NO;
[super touchesEnded:touches withEvent:event];
}

-(void)moveToPreviousItem{
NSLog(@"Move To Previous Item");
}
-(void)moveToNextItem{
NSLog(@"Move To Next Item");
}

Hint: use the CODE tags[]

bigga
Aug 18, 2010, 08:49 PM
You guys just saved my day. ;)

ianray
Aug 19, 2010, 05:08 PM
iOS 3.2 and above include UIGestureRecognizer, and notably, UISwipeGestureRecognizer.

shruthi-sh
Sep 2, 2010, 01:51 PM
@all - My UI is a scrollable tableview which i wanna swipe to next or previous pages. When I tried the above, the swiping action works only outside the tableview, at the borders of the screen. Could u suggest any changes so that I could apply for swipes anywhere on the screen?

Thanks,
Shruthi

bigga
Sep 3, 2010, 03:55 AM
The reason why this trick works only outside of the tableview is because tableview (which is a subclass of UIScrollView) overtakes the swipe handling.

The simplest solution might be to customize (i.e. extends) UITableView to handle the gesture.
(see: http://www.iphonedevsdk.com/forum/iphone-sdk-development/15668-how-detect-touch-table-view-header-view.html)

However, it is unusual if you swipe across a tableview (or a cell) to change the screen.
Standard behavior when you swipe across a cell is to delete the cell.