开发者

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:

  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.


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


  1. Update data source
  2. Insert row at bottom
  3. 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)

    })

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜