Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problems using UIPanGestureRecognizer in UITableViewCell

I'm trying to implement a UIPanGestureRecognizer in my UITableViewController to use for a swipe to delete animation. Similar to the swipe to delete used in the Clear app, where if you swipe a UITableViewCell in left or right the cell moves and gets deleted.

I have tried implementing this in my UITableViewCell subclass but it never seems to receive the event.

This is the code I put in my UITableViewCell subclass to try this functionality. In my init method

UIGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    recognizer.delegate = self;
    [self addGestureRecognizer:recognizer];

and then the methods to handle it:

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer {
CGPoint translation = [gestureRecognizer translationInView:self.superview];
//might have to change view to tableView
//check for the horizontal gesture
if (fabsf(translation.x) > fabsf(translation.y)) {
    return YES;
    NSLog(@"Panning");
}
return NO;
}

- (void)handlePan:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
    //if the gesture has just started record the center location
    NSLog(@"handlePan");
    _originalCenter = self.center; //Declared as a CGPoint at the top of my TableViewCell
}

if (recognizer.state == UIGestureRecognizerStateChanged) {
    //translate the center (aka translate from the center of the cell)
    CGPoint translation = [recognizer translationInView:self];
    self.center = CGPointMake(_originalCenter.x + translation.x, _originalCenter.y);
    // determine whether the item has been dragged far enough to delete/complete

}

if (recognizer.state == UIGestureRecognizerStateEnded) {
    // the frame this cell would have had before being dragged
    CGRect originalFrame = CGRectMake(0, self.frame.origin.y, self.bounds.origin.x, self.bounds.size.height);
    [UIView animateWithDuration:0.2 animations:^{
        self.frame = originalFrame;}
     ];
}
}

The Cells don't move at all though. Not really sure what's going on here

like image 420
cherbear Avatar asked Mar 12 '13 20:03

cherbear


People also ask

What is a uitableviewcell?

The visual representation of a single row in a table view. A UITableViewCell object is a specialized type of view that manages the content of a single table row. You use cells primarily to organize and present your app’s custom content, but UITableViewCell provides some specific customizations to support table-related behaviors, including:

How to reload data from uitableviewcontroller?

Were you using a UITableViewController? One of the few things it does is call reloadData () on the table view. Now you have to do it yourself. Place it after you assign the data source to the table view.

Should I use a scroll view or a UITableView?

For example, many developers make their life harder using a scroll view when a UITableView would be a better choice. Finally, architecture is crucial for table views. The code of the table view data source often ends inside view controllers when it should go into a separate class.

What is the uitableviewdatasource protocol?

While a table view offers many sophisticated features, The UITableViewDataSource protocol has only two required methods. Implementing these two is enough to have a working table view. A UITableView instance calls these two methods to request the information it needs, piece by piece.


2 Answers

If you don't want the cell's swipe gesture to happen simultaneously with the table view scroll gesture, then add a pan gesture to your cell and make it a delegate:

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

And implement the following delegate method to only start if the pan is horizontal:

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    // note: we might be called from an internal UITableViewCell long press gesture

    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {

        UIPanGestureRecognizer *panGestureRecognizer = (UIPanGestureRecognizer*)gestureRecognizer;
        UIView *cell = [panGestureRecognizer view];
        CGPoint translation = [panGestureRecognizer translationInView:[cell superview]];

        // Check for horizontal gesture
        if (fabs(translation.x) > fabs(translation.y))
        {
            return YES;
        }

    }

    return NO;
}

Swift3 ..

override func awakeFromNib() {
    super.awakeFromNib()
    // do not use, say, layoutSubviews as layoutSubviews is called often
    let p = UIPanGestureRecognizer(target: self, action: #selector(yourPan))
    p.delegate = self
    contentView.addGestureRecognizer(p)
    }
}

override func gestureRecognizerShouldBegin(_ g: UIGestureRecognizer) -> Bool {
    if (g.isKind(of: UIPanGestureRecognizer.self)) {
        let t = (g as! UIPanGestureRecognizer).translation(in: contentView)
        let verticalness = abs(t.y)
        if (verticalness > 0) {
            print("ignore vertical motion in the pan ...")
            print("the event engine will >pass on the gesture< to the scroll view")
            return false
        }
    }
    return true
}
like image 188
Jason Moore Avatar answered Oct 19 '22 02:10

Jason Moore


You need the following method in order for the gesture to be detected in sync with the scrollView's panGesture:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
   return YES; //otherGestureRecognizer is your custom pan gesture
}

Remember to set the panGesture.delegate to your viewController. (Updated with OlivaresF's comment.)

like image 32
Mark Avatar answered Oct 19 '22 04:10

Mark