Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scroll to last UITableViewCell using scrollToRowAtIndexPath:atScrollPosition:animated using NSFetchedResultsControllerDelegate methods

I am adding a new item to the bottom of a UITableView and after inserting the item, I want the UITableView to scroll to the very bottom to display the newly inserted item. New items are saved to Core Data and the UITableView is automatically updated using NSFetchedResultsController.

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
   atIndexPath:(NSIndexPath *)indexPath
 forChangeType:(NSFetchedResultsChangeType)type
  newIndexPath:(NSIndexPath *)newIndexPath
{
  switch (type) {
    case NSFetchedResultsChangeInsert:
        NSLog(@"*** controllerDidChangeObject - NSFetchedResultsChangeInsert");
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];

    //THIS IS THE CODE THAT DOESN'T WORK
    [self.tableView scrollToRowAtIndexPath:newIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

        break;

   ....
}

This leads to an out of bounds error, I can't seem to make it work. I can scroll to the second to last comment by adjusting the row of the index path, but I can't get to the very last item.

Basically, I'm adding a comment to a table of comments and after a comment is added, I want the table to scroll to the most recent comment.

like image 496
djblue2009 Avatar asked Jun 20 '12 21:06

djblue2009


1 Answers

You need to call endUpdates so that the tableView can calculate its new sections and rows. A simple case would look like this:

[self.tableView beginUpdates];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:insertedIndexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
[self.tableView scrollToRowAtIndexPath:insertedIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];

As you use NSFetchedResultsController, it is a bit more complicated, as the calls do beginUpdates, insertRowsAtIndexPaths:withRowAnimation:, and endUpdates are typically in different delegate methods. What you could do then is

  1. add a property insertedIndexPath to store the inserted index path
  2. after the -insertRowsAtIndexPaths:withRowAnimation: call in -controller:didChangeObject:atIndexPath:, add

    self.insertedIndexPath = insertedIndexPath;
    
  3. after [self.tableView endUpdates] in -controllerDidChangeContent:, add

    if (self.insertedIndexPath) {
        [self.tableView scrollToRowAtIndexPath:self.insertedIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
        self.insertedIndexPath = nil;
    }
    
like image 67
Tammo Freese Avatar answered Oct 21 '22 19:10

Tammo Freese