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 t开发者_Go百科he 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?
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.
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];
}
Other techniques, including those mentioned under this question did not work for me. This did however:
- Add the new item to the internal dataSource collection.
- 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.
- Immediately call tableView:reloadData:
- Now the new item is in this table but will visually appear empty (due to the flag).
- Check to see if this new item is visible using tableView.indexPathsForVisibleRows.
- 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)
- If it wasn't on screen scroll it into view with tableView:scrollToRowAtIndexPath: but don't immediately call reloadRowsAtIndexPath...
- 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.
Remeber to do this in the main thread otherwise it won't scroll to the required position.
- Update data source
- Insert row at bottom
- Scroll to bottom
Example:
YOUR_ARRAY.append("new string")
tableView.insertRows(at: [IndexPath(row: YOUR_ARRAY.count-1, section: 0)], with: .automatic)
tableView.scrollToRow(at: IndexPath(row: YOUR_ARRAY.count-1, section: 0), at: UITableViewScrollPosition.bottom, animated: true)
More generally, to scroll to the bottom:
NSIndexPath *scrollIndexPath = [NSIndexPath indexPathForRow:([self.table numberOfRowsInSection:([self.table numberOfSections] - 1)] - 1) inSection:([self.table numberOfSections] - 1)];
[self.table scrollToRowAtIndexPath:scrollIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
This works for me. Instead of inserting a row I just highlight it (by fading it in out.) The principle is the same, though.
if let definiteIndexPath = indexPathDelegate.getIndexPath(toDoItem) {
UIView.animateWithDuration(0.5, delay: 0, options: UIViewAnimationOptions.CurveEaseInOut, animations: {
self.tableView.scrollToRowAtIndexPath(definiteIndexPath, atScrollPosition: .Middle, animated: false)
}, completion: {
(finished: Bool) -> Void in
// Once the scrolling is done fade the text out and back in.
UIView.animateWithDuration(5, delay: 1, options: .Repeat | .Autoreverse, animations: {
self.tableView.reloadRowsAtIndexPaths([definiteIndexPath], withRowAnimation: UITableViewRowAnimation.Fade)
}, completion: nil)
})
}
精彩评论