Detecting horizontal swipe in a UITableView

Discussion in 'iOS Programming' started by lutius, Jul 28, 2008.

  1. macrumors newbie

    Joined:
    Jul 28, 2008
    #1
    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

    Code:
    #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 ?
     
  2. thread starter macrumors newbie

    Joined:
    Jul 28, 2008
    #2
    Never mind, I ended up with this, which apparently works well.
    -------------
    Code:
    #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];
    }
    
     
  3. macrumors newbie

    Joined:
    Oct 31, 2009
    #3
    Lutius You are the Man! Thank you! I had to change it a little

    Code:
    #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];
    }
    Code:
    -(void)moveToPreviousItem{
    	NSLog(@"Move To Previous Item");
    }
    -(void)moveToNextItem{
    	NSLog(@"Move To Next Item");
    }
    Hint: use the CODE tags[]
     
  4. macrumors newbie

    Joined:
    Apr 15, 2008
  5. macrumors 6502

    Joined:
    Jun 22, 2010
    Location:
    @
    #5
    iOS 3.2 and above include UIGestureRecognizer, and notably, UISwipeGestureRecognizer.
     
  6. macrumors newbie

    Joined:
    Sep 2, 2010
    #6
    @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
     
  7. macrumors newbie

    Joined:
    Apr 15, 2008
    #7
    Its the UITableView's fault

    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/i...-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.
     

Share This Page