Swipe to Reveal Redux

Episode #110 | 12 minutes | published on March 6, 2014
Subscribers Only
In this episode we fix the problem of a scroll view blocking touches to a UITableViewCell by forwarding touch events from the scroll view and onto a delegate, which manages the cell's highlighted state properly.

Errata

  • In the episode I create a strong reference to the tableView from a cell. In this way, I unintentionally create a retain cycle. Since UITableView retains its cells, a weak pointer is appropriate here. Thanks to Scott Williams for pointing this out.

Episode Links

Catching Taps in a Scroll View

Here we subclass UIScrollView into our own class, BSTapScrollView. It implements these methods:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesBegan:touches withEvent:event];

    if (!self.dragging) {
        [self.tapDelegate tapScrollView:self touchesBegan:touches withEvent:event];
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesMoved:touches withEvent:event];

    [self.tapDelegate tapScrollView:self touchesCancelled:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    [self.tapDelegate tapScrollView:self touchesCancelled:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Touch on scroll view ended");
    if (!self.dragging) {
        [self.tapDelegate tapScrollView:self touchesEnded:touches withEvent:event];
    } else {
        [super touchesEnded:touches withEvent:event];
    }
}

Note the use of a delegate that handles the tap events. The delegate is defined as:


@protocol BSTapScrollViewDelegate <NSObject>

@optional

- (void)tapScrollView:(BSTapScrollView *)scrollView touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)tapScrollView:(BSTapScrollView *)scrollView touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)tapScrollView:(BSTapScrollView *)scrollView touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

@end

To get this to work, we'll set our cell up as the tapDelegate for our scroll view:

@interface MailMessageCell () <BSTapScrollViewDelegate> ...

And in awakeFromNib...

self.scrollView.tapDelegate = self;

Managing the Highlighted State

#pragma mark - BSTapScrollViewDelegate

- (void)tapScrollView:(BSTapScrollView *)scrollView touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Setting highlighted...");

    if (_isOpen) {
    } else {
        [self setHighlighted:YES animated:YES];
    }
}

- (void)tapScrollView:(BSTapScrollView *)scrollView touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"Setting normal...");
    [self setHighlighted:NO animated:NO];
}

- (void)tapScrollView:(BSTapScrollView *)scrollView touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if (_isOpen) {
        return;
    }
    NSLog(@"did select....");
    NSIndexPath *indexPath = [self.tableView indexPathForCell:self];
    [self setHighlighted:NO animated:NO];
    [self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
    [self.tableView.delegate tableView:self.tableView didSelectRowAtIndexPath:indexPath];

    [[NSNotificationCenter defaultCenter] postNotificationName:RevealCellDidOpenNotification
                                                        object:self];
}
blog comments powered by Disqus