Skip to content

Instantly share code, notes, and snippets.

@calebd
Last active December 20, 2015 05:18
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save calebd/6076663 to your computer and use it in GitHub Desktop.
Save calebd/6076663 to your computer and use it in GitHub Desktop.
Rdio table view scrolling

Step 1: Configure the table view.

  • Set a view as the table footer
  • Set the background color to clear.

Step 2: Set the default table view values when your view loads. The values and variables seen here are explained below.

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.tableView.contentInset = UIEdgeInsetsMake(CGRectGetMaxY(self.headerView.frame) - 43.0, 0.0, 0.0, 0.0);
    self.tableView.scrollIndicatorInsets = self.tableView.contentInset;
    self.tableView.contentOffset = CGPointMake(0.0, -CGRectGetMaxY(self.headerView.frame) + 43.0);
}

Step 3: Update the table footer frame and content insets properties every time your view lays itself out or any time your table view content changes.

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    
    // Update footer view frame
    UIView *footerView = self.tableView.tableFooterView;
    footerView.frame = CGRectMake(0.0, 0.0, self.tableView.bounds.size.width, self.tableView.bounds.size.height);
    self.tableView.tableFooterView = footerView;
    
    // Update content insets
    UIEdgeInsets insets = self.tableView.contentInset;
    if (self.tableView.contentSize.height - footerView.bounds.size.height > self.tableView.bounds.size.height) {
      insets.bottom = -self.tableView.bounds.size.height;
    }
    else {
      insets.bottom = self.tableView.bounds.size.height - self.tableView.contentSize.height;
    }
    self.tableView.contentInset = insets;
}

Step 4: Update scroll indicator insets every time the scroll region change.

  • The value 44.0 is the height of the region you want to remain uncovered during scrolling
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    CGFloat offset = scrollView.contentOffset.y;
    CGFloat base = self.headerView.bounds.size.height - 44.0;
    CGFloat delta = base + offset;
    scrollView.scrollIndicatorInsets = UIEdgeInsetsMake(fmaxf(0.0, base - delta), 0.0, 0.0, 0.0);
}

Step 5: Tell the scroll view where to land when scrolling is done.

  • The value headerView is the view that is static behind the table view.
  • The value 43.0 is one less than the height from above (44.0) that is the height of the region you wish to remain uncovered. This is one less because UITableView puts a 1 point border at the top of its first cell that is normally hidden from view. Handling the value like this makes it such that that 1 point border is below the headerView when the table view is at rest.
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    if ((*targetContentOffset).y > 0.0 || (*targetContentOffset).y < -self.headerView.bounds.size.height) {
        return;
    }
    CGFloat middle = self.headerView.bounds.size.height / 2.0;
    if (velocity.y == 0.0) {
        if (-(*targetContentOffset).y > middle) {
            (*targetContentOffset).y = -CGRectGetMaxY(self.headerView.frame) + 43.0;
        }
        else {
            (*targetContentOffset).y = -1.0;
        }
    }
    else if (velocity.y > 0) {
        (*targetContentOffset).y = -1.0;
    }
    else {
        (*targetContentOffset).y = -CGRectGetMaxY(self.headerView.frame) + 43.0;
    }
}
@dmishe
Copy link

dmishe commented Jul 25, 2013

Hey Caleb, thanks for sharing this! I work with Chris on similar problem. This solution looks interesting, I must say though, have you tried placing a header view in front of table view, then on scroll, you just shrink that view until it reaches 0 height, and vice versa to it's full height?

@calebd
Copy link
Author

calebd commented Jul 26, 2013

I haven't. The thing to look out for there is changing the size of a table header or footer view has no effect until you set that view as the header view over again. I don't know how that would behave during scroll events.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment