2

I'm using UIPanGestureRecognizer to pan my contentView on a UICollectionViewCell. I'm implementing a swipe gesture, from both sides. I'm using a pan because I want to be able to bounce (animate) the view back to its origin.

The UICollectionView is a single section with rows where each row is a single item cell (think table).

The issue is as I scroll down my UICollectionView, I inadvertently cause my cells to move given the ever so little drag translation that happens. I've tried implementing UIScrollViewDelegate methods to try to prevent cells from inadvertently moving during scroll, but even the 'touching of the cell' edge case still fires causing the cell to pan slightly. It feels wrong because as you scroll and your thumb touches the cell, you see a number of cells pan around.

Are there any good ideas on how to prevent this sensitivity while scrolling? For example, the default Apple Mail.app doesn't seem to have this problem as you scroll; there seems to be some kind of resistance built in.

A few ideas:

  • apply some resistance function for some beginning k width on the x axis. Try to do this for velocity as well
  • if the velocity is not enough to get the view over the resistance "hump".
  • Try to use a UIScrollView instead of pan gesture recognizer, but then I need to somehow support swiping on the other side as well.
  • Should I think of using UIKit Dynamics for this?

Any ideas would be appreciated.

bneely
  • 9,083
  • 4
  • 38
  • 46
samonderous
  • 649
  • 1
  • 10
  • 22

1 Answers1

0

Try setting the UICollectionView's pan gesture to be required to fail for your UICollectionViewCell's to be valid. Using this method:

// create a relationship with another gesture recognizer that will prevent this gesture's actions from being called until otherGestureRecognizer transitions to UIGestureRecognizerStateFailed
// if otherGestureRecognizer transitions to UIGestureRecognizerStateRecognized or UIGestureRecognizerStateBegan then this recognizer will instead transition to UIGestureRecognizerStateFailed
// example usage: a single tap may require a double tap to fail
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;

Maybe by adding a property on the cell that you pass when it's created?

@interface YourCollectionViewCell : UICollectionViewCell
@property (weak, nonatomic) UIGestureRecognizer *blockingGestureRecognizer;

@property (strong, nonatomic) UIGestureRecognizer *internalSwipeGestureRecognizer;
@end

@implementation YourCollectionViewCell
- (void)setBlockingGestureRecognizer:(UIGestureRecognizer *)blockingGestureRecognizer {
    _blockingGestureRecognizer = blockingGestureRecognizer;
    [self.internalSwipeGestureRecognizer requireGestureRecognizerToFail:blockingGestureRecognizer];
}
@end

@interface YourViewController : UIViewController

#pragma mark - UICollectionViewDataSource

- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:YourCollectionViewCell.identifier forIndexPath:indexPath];

    cell.blockingGestureRecognizer = collectionView.panGestureRecognizer;

    return cell;
}
@end

Full warning, I have not compiled or tested this approach but I think it should work. :)

Matt Robinson
  • 799
  • 7
  • 22