UITableViewRowAnimation is ignored

2020-02-09 18:04发布

问题:

I'm using NSFetchedResultsController to populate my table. The data in my table is sorted according to the timestamp in the ascending order (latest message at the bottom). More data is loaded via "infinite scroll" to the top: e.g. when user scrolls past the top, more messages are loaded. My NSFetchedResultsControllerDelegate is defined as usual, as recommended in the apple documentation: new rows are inserted via

- (void)controller:(NSFetchedResultsController*)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath*)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath*)newIndexPath
{
    switch(type) {
        case NSFetchedResultsChangeInsert:
            NSLog(@"insertion at row %d", newIndexPath.row);
            [self.table insertRowsAtIndexPaths:@[newIndexPath]
                              withRowAnimation:UITableViewRowAnimationNone];

            break; 

Now here is my problem: when new rows are inserted, they are always animated as sliding "down". On the infinite scroll upwards it looks bad. That happens regardless of whether I pass UITableViewRowAnimationNone, UITableViewRowAnimationTop or UITableViewRowAnimationBottom as the parameter - that option seems to be ignored entirely.

Any ideas how to animate the table properly?

回答1:

Please try as below.

[CATransaction setDisableActions:YES];
[self.table insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationNone];
[CATransaction setDisableActions:NO]; // reset to original value


回答2:

So I've figured it out.

WWDC 2011 talk "Advanced Table View Techniques" explicitly says that UITableViewRowAnimationNone does not mean no animation (:

As if it made sense.

The animation parameter merely defines how the row is inserted into the space (e.g. slide from the right/left/etc), the transitions to create that space are animated regardless of what user wants.

So yeah, there is no way to insert/delete/refresh individual cells, and reloadData is the way to go. I love you, Apple.

Now according to many answers on stackoverflow there is also no way to insert content at the top of the table without changing the current view (e.g. seemlessly insert stuff with no changes to what user sees at all). The best one can do is to change the contentOffset after the new data have arrived.



回答3:

I found a way to disable insert/delete cells animation.

    [UIView setAnimationsEnabled:NO];
    [_tableView beginUpdates];

    [_table insertCell...];
    [_table removeCell...]

    [_table endUpdates];
    [UIView setAnimationsEnabled:YES];

It's perfectly doing work.



回答4:

As of iOS 7.0, you can wrap the code in a performWithoutAnimation: block, like so:

[UIView performWithoutAnimation:^{
                    [self.tableView beginUpdates];
                    [self.tableView deleteRowsAtIndexPaths:rowsToRemove withRowAnimation:UITableViewRowAnimationNone];
                    [self.tableView endUpdates];
                }];


回答5:

Are you breaking the data into sections? If you are, check your implementation of controller:didChangeSection:atIndex:forChangeType: as new section inserts will be animated with the animation types used in that method, not controller:didChangeObject:atIndexPath:forChangeType:newIndexPath:.