Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView scroll to bottom to see insertion animation

I have a UITableView that I am adding a row to with an animation (using insertRowsAtIndexPaths:withRowAnimation:). This is all good as long as the table is not longer than the screen.

If it is bigger than the screen then I am trying to scroll to the bottom, but it is not quite working how I want. If I scroll to the new row after it is added I miss the animation. If I try to scroll to that indexPath before it is added it throws an exception (about it not being a valid indexPath)

Is there a solution to this other than adding a blank row?

like image 368
Nathan Avatar asked Sep 30 '10 02:09

Nathan


4 Answers

I had this same issue. Here was my solution.

First - Update your data source

Second -

NSIndexPath *path = [NSIndexPath indexPathForRow:([arrayWhichFeeds count] - 1 inSection:0]];
NSArray *paths = [NSArray arrayWithObject:path];
[myTableView insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop]; 
[myTableView scrollToRowAtIndexPath:path atScrollPosition:UITableViewScrollPositionBottom animated:YES];

*Please note that this IS NOT wrapped in the [tableView beginUpdades] and [tableView endUpdates] code. If you do it will not work as desired.

Give it a try, it should animate in the new rows from the bottom while scrolling to them.

like image 100
CaseyB Avatar answered Oct 21 '22 05:10

CaseyB


Yes there is a solution without adding a blank row.

Note: In the code, I consider that there is only 1 section but many rows. You can modify the code to manage multiple sections as well.

- (void)theMethodInWhichYouInsertARowInTheTableView
{
     //Add the object in the array which feeds the tableview
     NSString *newStringObject = @"New Object";
     [arrayWhichFeeds addObject:newStringObject];

     [myTableView beginUpdates]; 

     NSArray *paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:([arrayWhichFeeds count] - 1) inSection:0]];
     [myTableView insertRowsAtIndexPaths:paths withRowAnimation:NO];

     [myTableView endUpdates];
     [myTableView reloadData];
     [myTableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:([arrayWhichFeeds count] - 1) inSection:0] atScrollPosition:UITableViewScrollPositionBottom animated:YES];   
}
like image 31
codes and moves Avatar answered Oct 21 '22 05:10

codes and moves


Other techniques, including those mentioned under this question did not work for me. This did however:

  1. Add the new item to the internal dataSource collection.
  2. Set a flag in the item that indicates it is "new". Force the display of the cell to show nothing when this flag is set.
  3. Immediately call tableView:reloadData:
  4. Now the new item is in this table but will visually appear empty (due to the flag).
  5. Check to see if this new item is visible using tableView.indexPathsForVisibleRows.
  6. If the item was is on screen immediately flip that "new" flag on the dataSource item to NO and call tableView:reloadRowsAtIndexPaths with an animation set. Now it will appear as if this item was just added. (you're done in this case)
  7. If it wasn't on screen scroll it into view with tableView:scrollToRowAtIndexPath: but don't immediately call reloadRowsAtIndexPath...
  8. Handle the message (void)scrollViewDidEndScrollingAnimation: and do that same reloadRowsAtIndexPath from step 6. I suspect this method is called anytime scrolling happens, so you'll have to detect when it's called from step 7 and when it's called because the user is scrolling around.

I worked this technique out (and wrote this answer) when I 1st started iOS development, but this did work out long term.

like image 30
Aardvark Avatar answered Oct 21 '22 07:10

Aardvark


Remeber to do this in the main thread otherwise it won't scroll to the required position.

like image 44
RRK Avatar answered Oct 21 '22 06:10

RRK