Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect horizontal panning in UITableView

I'm using a UIPanGestureRecognizer to recognize horizontal sliding in a UITableView (on a cell to be precise, though it is added to the table itself). However, this gesture recognizer obviously steals the touches from the table. I already got the pangesturerecognizer to recognize horizontal sliding and then snap to that; but if the user starts by sliding vertical, it should pass all events from that touch to the tableview.

One thing i have tried was disabling the recognizer, but then it wouldn't scroll untill the next touch event. So i'd need it to pass the event right away then.

Another thing i tried was making it scroll myself, but then you will miss the persistent speed after stopping the touch.

Heres some code:

//In the viewdidload method UIPanGestureRecognizer *slideRecognizer = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(sliding:)]; [myTable addGestureRecognizer:slideRecognizer];    -(void)sliding:(UIPanGestureRecognizer *)recognizer {     if (recognizer.state == UIGestureRecognizerStateBegan)     {     CGPoint translation = [recognizer translationInView:favoritesTable];     if (sqrt(translation.x*translation.x)/sqrt(translation.y*translation.y)>1) {         horizontalScrolling = YES; //BOOL declared in the header file         NSLog(@"horizontal");         //And some code to determine what cell is being scrolled:         CGPoint slideLocation = [recognizer locationInView:myTable];         slidingCell = [myTable indexPathForRowAtPoint:slideLocation];         if (slidingCell.row == 0) {             slidingCell = nil;         }      }     else     {         NSLog(@"cancel");     }      if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled)     {     horizontalScrolling = NO;     }       if (horizontalScrolling)     {         //Perform some code     }     else     {     //Maybe pass the touch from here; It's panning vertically     }  } 

So, any advice on how to pass the touches?

Addition: I also thought to maybe subclass the tableview's gesture recognizer method, to first check if it's horizontal; However, then i would need the original code, i suppose... No idea if Apple will have problems with it. Also: I didn't subclass the UITableView(controller), just the cells. This code is in the viewcontroller which holds the table ;)

like image 887
Erik S Avatar asked Mar 24 '11 22:03

Erik S


2 Answers

I had the same issue and came up with a solution that works with the UIPanGestureRecognizer.

In contrast to Erik I've added the UIPanGestureRecognizer to the cell directly, as I need just one particular cell at once to support the pan. But I guess this should work for Erik's case as well.

Here's the code.

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {     UIView *cell = [gestureRecognizer view];     CGPoint translation = [gestureRecognizer translationInView:[cell superview]];      // Check for horizontal gesture     if (fabsf(translation.x) > fabsf(translation.y))     {         return YES;     }      return NO; } 

The calculation for the horizontal gesture is copied form Erik's code – I've tested this with iOS 4.3.

Edit: I've found out that this implementation prevents the "swipe-to-delete" gesture. To regain that behavior I've added check for the velocity of the gesture to the if-statement above.

if ([gestureRecognizer velocityInView:cell].x < 600 && sqrt(translate... 

After playing a bit on my device I came up with a velocity of 500 to 600 which offers in my opinion the best user experience for the transition between the pan and the swipe-to-delete gesture.

like image 170
Florian Mielke Avatar answered Sep 30 '22 07:09

Florian Mielke


My answer is the same as Florian Mielke's, but I've simplified and corrected it some.

How to use:

Simply give your UIPanGestureRecognizer a delegate (UIGestureRecognizerDelegate). For example:

UIPanGestureRecognizer *panner = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panDetected:)]; panner.delegate = self; [self addGestureRecognizer:panner]; 

Then have that delegate implement the following method:

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {     CGPoint translation = [(UIPanGestureRecognizer *)gestureRecognizer translationInView:gestureRecognizer.view.superview];     return fabsf(translation.x) > fabsf(translation.y); } 
like image 37
Thane Brimhall Avatar answered Sep 30 '22 07:09

Thane Brimhall