Episode #106

UITableViewCell Swipe Action

11 minutes
Published on February 6, 2014

This video is only available to subscribers. Get access to this video and 572 others.

In this episode I cover how to extend UITableViewCells to provide a swipe action, marking an item as read or unread. Combined with a nifty little progress animation, this adds functionality to your table view cells without requiring extra buttons or action sheets.

Episode Links

Adding the scroll view

- (void)layoutSubviews {
    [super layoutSubviews];

    if (_scrollView == nil) {
        _scrollView = [[UIScrollView alloc] initWithFrame:self.contentView.bounds];
        _scrollView.contentSize = self.contentView.frame.size;
        _scrollView.alwaysBounceHorizontal = YES;
        _scrollView.delegate = self;

        [self.contentView insertSubview:_scrollView atIndex:0];
    }

    [self.scrollView addSubview:self.textLabel];  // this is really just lazy.  we should create our own label

    ...
}

Note that because our scroll view's contentSize is the same as bounds we have to set alwaysBounceHorizontal to YES otherwise our scroll view will have no behavior whatsoever.

Preventing from scrolling right

We only want to provide the left swipe behavior, so we implement scrollViewDidScroll: with:

    if (scrollView.contentOffset.x < 0) {
        scrollView.contentOffset = CGPointZero;
    }

Next we need to update our indicator with the progress of our swipe...

Updating Progress of the Swipe Action

    if (!self.hasChangedUnreadStatus) {
        const CGFloat MaxDistance = 40;
        CGFloat progress = MIN(1, scrollView.contentOffset.x / MaxDistance);
        [self.unreadIndicator setFillPercent:progress];

        if (progress >= 1.0) {
            self.unreadIndicator.hasRead = !self.unreadIndicator.hasRead;
            [self.unreadIndicator setFillPercent:0];
            self.hasChangedUnreadStatus = YES;
        }
    }

We're using a flag here to avoid rapidly toggling the unread status once we've reached the threshold. We need a way to set this back to NO after the scrolling animation finishes, so we implement another UIScrollViewDelegate method:


- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    self.hasChangedUnreadStatus = NO;
}

The unread indicator

The unread indicator here is just a work in progress and not really the focus of the episode (it has a bug, as you saw in the recording). I'd challenge you to come up with other useful ways of showing the progress of the swipe. Perhaps also experiment with sound.