[cocoa-touch] Have a reloadData for a UITableView animate when changing

I have a UITableView that has two modes. When we switch between the modes I have a different number of sections and cells per section. Ideally, it would do some cool animation when the table grows or shrinks.

Here is the code I tried, but it doesn't do anything:

CGContextRef context = UIGraphicsGetCurrentContext(); 
[UIView beginAnimations:nil context:context]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:0.5]; 

[self.tableView reloadData];
[UIView commitAnimations];

Any thoughts on how I could do this?

This question is related to cocoa-touch animation

The answer is


The way to approach this is to tell the tableView to remove and add rows and sections with the

insertRowsAtIndexPaths:withRowAnimation:,
deleteRowsAtIndexPaths:withRowAnimation:,
insertSections:withRowAnimation: and
deleteSections:withRowAnimation:

methods of UITableView.

When you call these methods, the table will animate in/out the items you requested, then call reloadData on itself so you can update the state after this animation. This part is important - if you animate away everything but don't change the data returned by the table's dataSource, the rows will appear again after the animation completes.

So, your application flow would be:

[self setTableIsInSecondState:YES];

[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];

As long as your table's dataSource methods return the correct new set of sections and rows by checking [self tableIsInSecondState] (or whatever), this will achieve the effect you're looking for.


If you want to add your own custom animations to UITableView cells, use

[theTableView reloadData];
[theTableView layoutSubviews];
NSArray* visibleViews = [theTableView visibleCells];

to get an array of visible cells. Then add any custom animation to each cell.

Check out this gist I posted for a smooth custom cell animation. https://gist.github.com/floprr/1b7a58e4a18449d962bd


I can't comment on the top answer, but a swift implementation would be:

self.tableView.reloadSections([0], with: UITableViewRowAnimation.fade)

you could include as many sections as you want to update in the first argument for reloadSections.

Other animations available from the docs: https://developer.apple.com/reference/uikit/uitableviewrowanimation

fade The inserted or deleted row or rows fade into or out of the table view.

right The inserted row or rows slide in from the right; the deleted row or rows slide out to the right.

left The inserted row or rows slide in from the left; the deleted row or rows slide out to the left.

top The inserted row or rows slide in from the top; the deleted row or rows slide out toward the top.

bottom The inserted row or rows slide in from the bottom; the deleted row or rows slide out toward the bottom.

case none The inserted or deleted rows use the default animations.

middle The table view attempts to keep the old and new cells centered in the space they did or will occupy. Available in iPhone 3.2.

automatic The table view chooses an appropriate animation style for you. (Introduced in iOS 5.0.)


For Swift 4

tableView.reloadSections([0], with: UITableView.RowAnimation.fade)

All of these answers assume that you are using a UITableView with only 1 section.

To accurately handle situations where you have more than 1 section use:

NSRange range = NSMakeRange(0, myTableView.numberOfSections);
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[myTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];

(Note: you should make sure that you have more than 0 sections!)

Another thing to note is that you may run into a NSInternalInconsistencyException if you attempt to simultaneously update your data source with this code. If this is the case, you can use logic similar to this:

int sectionNumber = 0; //Note that your section may be different

int nextIndex = [currentItems count]; //starting index of newly added items

[myTableView beginUpdates];

for (NSObject *item in itemsToAdd) {
    //Add the item to the data source
    [currentItems addObject:item];

    //Add the item to the table view
    NSIndexPath *path = [NSIndexPath indexPathForRow:nextIndex++ inSection:sectionNumber];
    [myTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationAutomatic];
}

[myTableView endUpdates];

Native UITableView animations in Swift

Insert and delete rows all at once with tableView.performBatchUpdates so they occur simultaneously. Building on the answer from @iKenndac use methods such as:

  • tableView.insertSections
  • tableView.insertRows
  • tableView.deleteSections
  • tableView.deleteRows

Ex:

 tableView.performBatchUpdates({
   tableView.insertSections([0], with: .top)
 })

This inserts a section at the zero position with an animation that loads from the top. This will re-run the cellForRowAt method and check for a new cell at that position. You could reload the entire table view this way with specific animations.

Re: the OP question, a conditional flag would have been needed to show the cells for the alternate table view state.


I can't comment on the top answer, but a swift implementation would be:

self.tableView.reloadSections([0], with: UITableViewRowAnimation.fade)

you could include as many sections as you want to update in the first argument for reloadSections.

Other animations available from the docs: https://developer.apple.com/reference/uikit/uitableviewrowanimation

fade The inserted or deleted row or rows fade into or out of the table view.

right The inserted row or rows slide in from the right; the deleted row or rows slide out to the right.

left The inserted row or rows slide in from the left; the deleted row or rows slide out to the left.

top The inserted row or rows slide in from the top; the deleted row or rows slide out toward the top.

bottom The inserted row or rows slide in from the bottom; the deleted row or rows slide out toward the bottom.

case none The inserted or deleted rows use the default animations.

middle The table view attempts to keep the old and new cells centered in the space they did or will occupy. Available in iPhone 3.2.

automatic The table view chooses an appropriate animation style for you. (Introduced in iOS 5.0.)


I believe you can just update your data structure, then:

[tableView beginUpdates];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView endUpdates];

Also, the "withRowAnimation" is not exactly a boolean, but an animation style:

UITableViewRowAnimationFade,
UITableViewRowAnimationRight,
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone,
UITableViewRowAnimationMiddle

Have more freedom using CATransition class.

It isn't limited to fading, but can do movements as well..


For example:

(don't forget to import QuartzCore)

CATransition *transition = [CATransition animation];
transition.type = kCATransitionPush;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.fillMode = kCAFillModeForwards;
transition.duration = 0.5;
transition.subtype = kCATransitionFromBottom;

[[self.tableView layer] addAnimation:transition forKey:@"UITableViewReloadDataAnimationKey"];

Change the type to match your needs, like kCATransitionFade etc.

Implementation in Swift:

let transition = CATransition()
transition.type = kCATransitionPush
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.fillMode = kCAFillModeForwards
transition.duration = 0.5
transition.subtype = kCATransitionFromTop
self.tableView.layer.addAnimation(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

Reference for CATransition

Swift 5:

let transition = CATransition()
transition.type = CATransitionType.push
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.fillMode = CAMediaTimingFillMode.forwards
transition.duration = 0.5
transition.subtype = CATransitionSubtype.fromTop
self.tableView.layer.add(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

Animating without reloadData() in Swift can be done like this (as of version 2.2):

tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
    // ...or here, if you need to add/remove the same amount of objects to/from somewhere
    indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
    numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()

in case you need to call reloadData() after the animation ends, you can embrace the changes in CATransaction like this:

CATransaction.begin()
CATransaction.setCompletionBlock({() in self.tableview.reloadData() })
tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove.count ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
     // ...or here, if you need to add/remove the same amount of objects to/from somewhere
     indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
     numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()
CATransaction.commit()

The logic is shown for the case when you delete rows, but the same idea works also for adding rows. You can also change animation to UITableViewRowAnimation.Left to make it neat, or choose from the list of other available animations.


UITableView has a field called 'indexPathsForVisibleRows' that you can use to animate the visible rows using the 'reloadItemsAtIndexPaths' method.

    guard let indexPaths = tableView.indexPathsForVisibleRows
    else { return }
    
    self.tableView.layoutIfNeeded()
    self.tableView.reloadItemsAtIndexPaths(indexPaths, animationStyle: .automatic)

Swift Implementation:

let range = NSMakeRange(0, self.tableView!.numberOfSections())
let indexSet = NSIndexSet(indexesInRange: range)
self.tableView!.reloadSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)

The way to approach this is to tell the tableView to remove and add rows and sections with the

insertRowsAtIndexPaths:withRowAnimation:,
deleteRowsAtIndexPaths:withRowAnimation:,
insertSections:withRowAnimation: and
deleteSections:withRowAnimation:

methods of UITableView.

When you call these methods, the table will animate in/out the items you requested, then call reloadData on itself so you can update the state after this animation. This part is important - if you animate away everything but don't change the data returned by the table's dataSource, the rows will appear again after the animation completes.

So, your application flow would be:

[self setTableIsInSecondState:YES];

[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];

As long as your table's dataSource methods return the correct new set of sections and rows by checking [self tableIsInSecondState] (or whatever), this will achieve the effect you're looking for.


I believe you can just update your data structure, then:

[tableView beginUpdates];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView endUpdates];

Also, the "withRowAnimation" is not exactly a boolean, but an animation style:

UITableViewRowAnimationFade,
UITableViewRowAnimationRight,
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone,
UITableViewRowAnimationMiddle

CATransition *animation = [CATransition animation];
animation.duration = .3;
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setDuration:.3];

[[_elementTableView layer] addAnimation:animation forKey:@"UITableViewReloadDataAnimationKey"];

[tableView reloadData];

The way to approach this is to tell the tableView to remove and add rows and sections with the

insertRowsAtIndexPaths:withRowAnimation:,
deleteRowsAtIndexPaths:withRowAnimation:,
insertSections:withRowAnimation: and
deleteSections:withRowAnimation:

methods of UITableView.

When you call these methods, the table will animate in/out the items you requested, then call reloadData on itself so you can update the state after this animation. This part is important - if you animate away everything but don't change the data returned by the table's dataSource, the rows will appear again after the animation completes.

So, your application flow would be:

[self setTableIsInSecondState:YES];

[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];

As long as your table's dataSource methods return the correct new set of sections and rows by checking [self tableIsInSecondState] (or whatever), this will achieve the effect you're looking for.


Animating without reloadData() in Swift can be done like this (as of version 2.2):

tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
    // ...or here, if you need to add/remove the same amount of objects to/from somewhere
    indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
    numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()

in case you need to call reloadData() after the animation ends, you can embrace the changes in CATransaction like this:

CATransaction.begin()
CATransaction.setCompletionBlock({() in self.tableview.reloadData() })
tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove.count ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
     // ...or here, if you need to add/remove the same amount of objects to/from somewhere
     indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
     numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()
CATransaction.commit()

The logic is shown for the case when you delete rows, but the same idea works also for adding rows. You can also change animation to UITableViewRowAnimation.Left to make it neat, or choose from the list of other available animations.


Swift 4 version for @dmarnel answer:

tableView.reloadSections(IndexSet(integer: 0), with: .automatic)

All of these answers assume that you are using a UITableView with only 1 section.

To accurately handle situations where you have more than 1 section use:

NSRange range = NSMakeRange(0, myTableView.numberOfSections);
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[myTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];

(Note: you should make sure that you have more than 0 sections!)

Another thing to note is that you may run into a NSInternalInconsistencyException if you attempt to simultaneously update your data source with this code. If this is the case, you can use logic similar to this:

int sectionNumber = 0; //Note that your section may be different

int nextIndex = [currentItems count]; //starting index of newly added items

[myTableView beginUpdates];

for (NSObject *item in itemsToAdd) {
    //Add the item to the data source
    [currentItems addObject:item];

    //Add the item to the table view
    NSIndexPath *path = [NSIndexPath indexPathForRow:nextIndex++ inSection:sectionNumber];
    [myTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationAutomatic];
}

[myTableView endUpdates];

Actually, it's very simple:

[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

From the documentation:

Calling this method causes the table view to ask its data source for new cells for the specified sections. The table view animates the insertion of new cells in as it animates the old cells out.


You might want to use:

Objective-C

[UIView transitionWithView: self.tableView
                  duration: 0.35f
                   options: UIViewAnimationOptionTransitionCrossDissolve
                animations: ^(void)
 {
      [self.tableView reloadData];
 }
                completion: nil];

Swift

UIView.transitionWithView(tableView,
                          duration: 0.35,
                          options: .TransitionCrossDissolve,
                          animations:
{ () -> Void in
    self.tableView.reloadData()
},
                          completion: nil);

Swift 3, 4 & 5

UIView.transition(with: tableView,
                  duration: 0.35,
                  options: .transitionCrossDissolve,
                  animations: { self.tableView.reloadData() }) // left out the unnecessary syntax in the completion block and the optional completion parameter

No hassles. :D

You can also use any of the UIViewAnimationOptionTransitions you want for cooler effects:

  • transitionNone
  • transitionFlipFromLeft
  • transitionFlipFromRight
  • transitionCurlUp
  • transitionCurlDown
  • transitionCrossDissolve
  • transitionFlipFromTop
  • transitionFlipFromBottom

For Swift 4

tableView.reloadSections([0], with: UITableView.RowAnimation.fade)

UITableView has a field called 'indexPathsForVisibleRows' that you can use to animate the visible rows using the 'reloadItemsAtIndexPaths' method.

    guard let indexPaths = tableView.indexPathsForVisibleRows
    else { return }
    
    self.tableView.layoutIfNeeded()
    self.tableView.reloadItemsAtIndexPaths(indexPaths, animationStyle: .automatic)

To reload all sections, not just one with custom duration.

User duration parameter of UIView.animate to set custom duration.

UIView.animate(withDuration: 0.4, animations: { [weak self] in
    guard let `self` = self else { return }
    let indexSet = IndexSet(integersIn: 0..<self.tableView.numberOfSections)
    self.tableView.reloadSections(indexSet, with: UITableView.RowAnimation.fade)
})

In my case, I wanted to add 10 more rows into the tableview (for a "show more results" type of functionality) and I did the following:

  NSInteger tempNumber = self.numberOfRows;
  self.numberOfRows += 10;
  NSMutableArray *arrayOfIndexPaths = [[NSMutableArray alloc] init];
  for (NSInteger i = tempNumber; i < self.numberOfRows; i++) {
    [arrayOfIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
  }
  [self.tableView beginUpdates];
  [self.tableView insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation:UITableViewRowAnimationTop];
  [self.tableView endUpdates];

In most cases, instead of "self.numberOfRows", you would usually use the count of the array of objects for the tableview. So to make sure this solution works well for you, "arrayOfIndexPaths" needs to be an accurate array of the index paths of the rows being inserted. If the row exists for any of this index paths, the code might crash, so you should use the method "reloadRowsAtIndexPaths:withRowAnimation:" for those index pathds to avoid crashing


If you want to add your own custom animations to UITableView cells, use

[theTableView reloadData];
[theTableView layoutSubviews];
NSArray* visibleViews = [theTableView visibleCells];

to get an array of visible cells. Then add any custom animation to each cell.

Check out this gist I posted for a smooth custom cell animation. https://gist.github.com/floprr/1b7a58e4a18449d962bd


You might want to use:

Objective-C

[UIView transitionWithView: self.tableView
                  duration: 0.35f
                   options: UIViewAnimationOptionTransitionCrossDissolve
                animations: ^(void)
 {
      [self.tableView reloadData];
 }
                completion: nil];

Swift

UIView.transitionWithView(tableView,
                          duration: 0.35,
                          options: .TransitionCrossDissolve,
                          animations:
{ () -> Void in
    self.tableView.reloadData()
},
                          completion: nil);

Swift 3, 4 & 5

UIView.transition(with: tableView,
                  duration: 0.35,
                  options: .transitionCrossDissolve,
                  animations: { self.tableView.reloadData() }) // left out the unnecessary syntax in the completion block and the optional completion parameter

No hassles. :D

You can also use any of the UIViewAnimationOptionTransitions you want for cooler effects:

  • transitionNone
  • transitionFlipFromLeft
  • transitionFlipFromRight
  • transitionCurlUp
  • transitionCurlDown
  • transitionCrossDissolve
  • transitionFlipFromTop
  • transitionFlipFromBottom

Actually, it's very simple:

[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

From the documentation:

Calling this method causes the table view to ask its data source for new cells for the specified sections. The table view animates the insertion of new cells in as it animates the old cells out.


Swift Implementation:

let range = NSMakeRange(0, self.tableView!.numberOfSections())
let indexSet = NSIndexSet(indexesInRange: range)
self.tableView!.reloadSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)

In my case, I wanted to add 10 more rows into the tableview (for a "show more results" type of functionality) and I did the following:

  NSInteger tempNumber = self.numberOfRows;
  self.numberOfRows += 10;
  NSMutableArray *arrayOfIndexPaths = [[NSMutableArray alloc] init];
  for (NSInteger i = tempNumber; i < self.numberOfRows; i++) {
    [arrayOfIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
  }
  [self.tableView beginUpdates];
  [self.tableView insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation:UITableViewRowAnimationTop];
  [self.tableView endUpdates];

In most cases, instead of "self.numberOfRows", you would usually use the count of the array of objects for the tableview. So to make sure this solution works well for you, "arrayOfIndexPaths" needs to be an accurate array of the index paths of the rows being inserted. If the row exists for any of this index paths, the code might crash, so you should use the method "reloadRowsAtIndexPaths:withRowAnimation:" for those index pathds to avoid crashing


The way to approach this is to tell the tableView to remove and add rows and sections with the

insertRowsAtIndexPaths:withRowAnimation:,
deleteRowsAtIndexPaths:withRowAnimation:,
insertSections:withRowAnimation: and
deleteSections:withRowAnimation:

methods of UITableView.

When you call these methods, the table will animate in/out the items you requested, then call reloadData on itself so you can update the state after this animation. This part is important - if you animate away everything but don't change the data returned by the table's dataSource, the rows will appear again after the animation completes.

So, your application flow would be:

[self setTableIsInSecondState:YES];

[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];

As long as your table's dataSource methods return the correct new set of sections and rows by checking [self tableIsInSecondState] (or whatever), this will achieve the effect you're looking for.


Swift 4 version for @dmarnel answer:

tableView.reloadSections(IndexSet(integer: 0), with: .automatic)

Have more freedom using CATransition class.

It isn't limited to fading, but can do movements as well..


For example:

(don't forget to import QuartzCore)

CATransition *transition = [CATransition animation];
transition.type = kCATransitionPush;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.fillMode = kCAFillModeForwards;
transition.duration = 0.5;
transition.subtype = kCATransitionFromBottom;

[[self.tableView layer] addAnimation:transition forKey:@"UITableViewReloadDataAnimationKey"];

Change the type to match your needs, like kCATransitionFade etc.

Implementation in Swift:

let transition = CATransition()
transition.type = kCATransitionPush
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.fillMode = kCAFillModeForwards
transition.duration = 0.5
transition.subtype = kCATransitionFromTop
self.tableView.layer.addAnimation(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

Reference for CATransition

Swift 5:

let transition = CATransition()
transition.type = CATransitionType.push
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.fillMode = CAMediaTimingFillMode.forwards
transition.duration = 0.5
transition.subtype = CATransitionSubtype.fromTop
self.tableView.layer.add(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

Native UITableView animations in Swift

Insert and delete rows all at once with tableView.performBatchUpdates so they occur simultaneously. Building on the answer from @iKenndac use methods such as:

  • tableView.insertSections
  • tableView.insertRows
  • tableView.deleteSections
  • tableView.deleteRows

Ex:

 tableView.performBatchUpdates({
   tableView.insertSections([0], with: .top)
 })

This inserts a section at the zero position with an animation that loads from the top. This will re-run the cellForRowAt method and check for a new cell at that position. You could reload the entire table view this way with specific animations.

Re: the OP question, a conditional flag would have been needed to show the cells for the alternate table view state.


To reload all sections, not just one with custom duration.

User duration parameter of UIView.animate to set custom duration.

UIView.animate(withDuration: 0.4, animations: { [weak self] in
    guard let `self` = self else { return }
    let indexSet = IndexSet(integersIn: 0..<self.tableView.numberOfSections)
    self.tableView.reloadSections(indexSet, with: UITableView.RowAnimation.fade)
})

CATransition *animation = [CATransition animation];
animation.duration = .3;
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setDuration:.3];

[[_elementTableView layer] addAnimation:animation forKey:@"UITableViewReloadDataAnimationKey"];

[tableView reloadData];