44
votes

In IOS6 I have the following code to scroll to the top of a UITableView

[tableView setContentOffset:CGPointZero animated:YES];

In IOS7 this doesn't work anymore. The table view isn't scrolled completely to the top (but almost).

12
Is it possible that what you're missing is 20 px from the new status bar style? This happened to me in a bunch of places - there is a bug fix in IB that makes a correct adjustment for the status bar. This can result in either 20 px on the bottom or on the top missinggillyD

12 Answers

127
votes

In iOS7, whole screen UITableView and UIScrollView components, by default, adjust content and scroll indicator insets to just make everything work. However, as you've noticed CGPointZero no longer represents the content offset that takes you to the visual "top".

Use this instead:

self.tableView.contentOffset = CGPointMake(0, 0 - self.tableView.contentInset.top);

Here, you don't have to worry about if you have sections or rows. You also don't tell the Table View to target the first row, and then wonder why it didn't show all of your very tall table header view, etc.

23
votes

Try this:

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
22
votes

Based on the accepted answer from @Markus Johansson, here is the Swift code version:

func scrollToTop() {
    if (self.tableView.numberOfSections > 0 ) {
        let top = NSIndexPath(row: Foundation.NSNotFound, section: 0)
        self.tableView.scrollToRow(at: top as IndexPath, at: .top, animated: true);
    }
}
17
votes

By the help from some other answers here I managed to get it working. To avoid a crash I must first check that there are some sections. NsNotFound can be used as a row index if the first section has no rows. Hopefully this should be a generic function to be placed in a UITableViewController:

-(void) scrollToTop
{
    if ([self numberOfSectionsInTableView:self.tableView] > 0)
    {
        NSIndexPath* top = [NSIndexPath indexPathForRow:NSNotFound inSection:0];
        [self.tableView scrollToRowAtIndexPath:top atScrollPosition:UITableViewScrollPositionTop animated:YES];
    }
}
4
votes
var indexPath = NSIndexPath(forRow: 0, inSection: 0)
self.sampleTableView.scrollToRowAtIndexPath(indexPath,
atScrollPosition: UITableViewScrollPosition.Top, animated: true)

or

self.sampleTableView.setContentOffset(CGPoint.zero, animated:false)
3
votes
float systemVersion= [[[UIDevice currentDevice] systemVersion] floatValue];

if(systemVersion >= 7.0f)
{
  self.edgesForExtendedLayout=UIRectEdgeNone;   
}

Try this code in viewDidLoad() method.

3
votes

Here is idStar's answer in updated Swift 3 syntax:

self.tableView.contentOffset = CGPoint(x: 0, y: 0 - self.tableView.contentInset.top)

With animation:

self.tableView.setContentOffset(CGPoint(x: 0, y: 0 - self.tableView.contentInset.top), animated: true)
3
votes

Swift 3

If you have table view headers CGPointZero may not work for you, but this always does the trick to scroll to top.

self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: UITableViewScrollPosition.top, animated: false)
2
votes

you can still use scrollToRowAtIndexPath: for the purpose

2
votes

I realize this has been answered but I just wanted to give another option:

CGRect frame = {{0, 0},{1, 1}};
[self.tableView scrollRectToVisible:frame animated:YES];

This always guarantees the UITableView will scroll to the top. The accepted answer:

NSIndexPath* top = [NSIndexPath indexPathForRow:NSNotFound inSection:0];
[self.tableView scrollToRowAtIndexPath:top atScrollPosition:UITableViewScrollPositionTop animated:YES];

was not working for me because I was scrolling to a tableHeaderView and not a cell.

Using scrollRectToVisible works on iOS 6 and 7.

1
votes

Swift 4 UITableViewExtension:

func scrollToTop(animated: Bool) {
    if numberOfSections > 0 {
        let topIndexPath = IndexPath(row: NSNotFound, section: 0)
        scrollToRow(at: topIndexPath, at: .top, animated: animated)
    }
}
0
votes

in swift I used:

self.tableView.setContentOffset(CGPointMake(0, 0), animated: true)

but @Alvin George's works great