0

I'm writing an iOS 5 app (in Xcode 4.3, using Storyboards and ARC) that has some table cells that need to respond to horizontal pans. I had a table setup that worked really well but then I needed to implement the same behavior on another scene. I figured the best-practices way would be to abstract out the gesture-recognizing and -handling code into subclasses. But now the tableView won't scroll, and the solution I had for this problem under the old method doesn't help.

I have a RestaurantViewController which inherits from UIViewController and has a property ULPanningTableView *tableView. Some of the table's cells are MenuItemCells and inherit from ULPanningTableViewCell. The table's delegate and data source are the RestaurantViewController.

ULPanningTableViewCell inherits from UITableViewCell and is pretty close to the original, the only difference being that it has properties to keep track of the cell's front and back views, and the custom backgrounds.

ULPanningTableView is a bit more complicated, since it has to set up the recognition and handling.

ULPanningTableView.h:

#import <UIKit/UIKit.h>

@interface ULPanningTableView : UITableView <UIGestureRecognizerDelegate>

@property (nonatomic) float openCellLastTX;
@property (nonatomic, strong) NSIndexPath *openCellIndexPath;

- (id)dequeueReusablePanningCellWithIdentifier:(NSString *)identifier;
- (void)handlePan:(UIPanGestureRecognizer *)panGestureRecognizer;
// ... some helpers for handlePan:

@end

and ULPanningTableView.m:

#import "ULPanningTableView.h"
#import "ULPanningTableViewCell.h"

@implementation ULPanningTableView

@synthesize openCellIndexPath=_openCellIndexPath, openCellLastTX=_openCellLastTX;

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

#pragma mark - Table View Helpers

- (id)dequeueReusablePanningCellWithIdentifier:(NSString *)identifier
{
    ULPanningTableViewCell *cell = (ULPanningTableViewCell *)[self dequeueReusableCellWithIdentifier:identifier];

    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    [panGestureRecognizer setDelegate:self];
    [cell addGestureRecognizer:panGestureRecognizer];

    return cell;
}

#pragma mark - UIGestureRecognizerDelegate protocol

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    // for testing: only allow UIScrollViewPanGestureRecognizers to begin
    NSString *gr = NSStringFromClass([gestureRecognizer class]);
    if ([gr isEqualToString:@"UIScrollViewPanGestureRecognizer"]) {
        return YES;
    } else {
        return NO;
    }
}

#pragma mark - panhandling

- (void)handlePan:(UIPanGestureRecognizer *)panGestureRecognizer
{
    // ...
}
// ... some helpers for handlePan:

@end

I've played around with gestureRecognizerShouldBegin:, because that was how I solved this problem back when these weren't separate classes (ULPanningTableView stuff was implemented inside RestaurantViewController and ULPanningTableViewCell was stuff was implemented in MenuItemCell. I would essentially return NO for gestures where the translationInView was more vertical than horizontal). Anyway, I can't get the table to scroll! I can get the pan gestures to be recognized if I return YES from gestureRecognizerShouldBegin:, or if I remove the UIGestureRecognizerDelegate implementation entirely.

I'm still a beginner in iOS, and in Objective-C, so I only have hunches based on things I've read, and I'm under the impression from a similar problem that the culprit is UIScrollViewPanGestureRecognizer doing voodoo with the responder chain...

I would greatly appreciate any light you can shed on this!

Spencer Williams
  • 902
  • 8
  • 26
  • Are you trying to move a view in the cell or are you trying to scroll the cell's contents horizontally? – NJones Apr 01 '12 at 17:45
  • Horizontal pan should move a view in the cell. I couldn't figure out how to interact with the cell's contents to show its `backgroundView`, so I'm moving a custom property of the cell `UIView *frontView`. Vertical pan should scroll the table. – Spencer Williams Apr 02 '12 at 08:08

1 Answers1

0

Ok, so I feel really silly. -handlePan: is already a method! I changed it to -handleCustomPan: and it will handle other pans normally. I'm not sure why it wasn't crashing, but there it is. Oh, and I had to keep the UIScrollViewPanGestureRecognizer edge case in -gestureRecognizerDidBegin::

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
    NSString *gr = NSStringFromClass([gestureRecognizer class]);
    if ([gr isEqualToString:@"UIScrollViewPanGestureRecognizer"]) {
        // allow scroll to begin
        return YES;
    } else if ([gr isEqualToString:@"UIPanGestureRecognizer"]){
        UIPanGestureRecognizer *panGR = (UIPanGestureRecognizer *)gestureRecognizer;
        // allow horizontal pans to begin
        ULPanningTableViewCell *cell = (ULPanningTableViewCell *)[panGR view];
        CGPoint translation = [panGR translationInView:[cell superview]];
        BOOL should = (fabs(translation.x) / fabs(translation.y) > 1) ? YES : NO;

        if (!should) {
            [self closeOpenCellAnimated:YES];
        }

        return should;

    } else {
        NSLog(@"%@",gestureRecognizer);
        return NO;
    }
}
Spencer Williams
  • 902
  • 8
  • 26