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 becauseUITableView
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 theheaderView
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;
}
}
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?