33

How would you anime - reloadData on UITableView? Data source is on UIFetchedResultsController so I can't play with – insertSections:withRowAnimation:, – deleteSections:withRowAnimation: wrapped in – beginUpdates, – endUpdates.

EDIT: I want to call - reloadData after NSFetchedResultsController refetch.

user500
  • 4,519
  • 6
  • 43
  • 56
  • 3
    Duplicate of this - http://stackoverflow.com/questions/419472/have-a-reloaddata-for-a-uitableview-animate-when-changing - good answers there – Oded Ben Dov Jun 28 '12 at 08:10

8 Answers8

83

I did category method.

- (void)reloadData:(BOOL)animated
{
    [self reloadData];

    if (animated) {

        CATransition *animation = [CATransition animation];
        [animation setType:kCATransitionPush];
        [animation setSubtype:kCATransitionFromBottom];
        [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
        [animation setFillMode:kCAFillModeBoth];
        [animation setDuration:.3];
        [[self layer] addAnimation:animation forKey:@"UITableViewReloadDataAnimationKey"];

    }
}
user500
  • 4,519
  • 6
  • 43
  • 56
  • Nice solution if you need some custom animation – voromax Jul 31 '12 at 23:01
  • Awesome solution! I have only one thing to add. In my case I was experiencing issues cause the TableView before the reloadData was scrolled all to the bottom, so when the animation happened it screwed up all the cells and the frame of the table. I could solve it making sure the tableView was scrolled all to the top before before reloadData: [self scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO]; – Pauls May 23 '13 at 23:20
  • Can I avoid, header being affected. I have a searchbar in the table header, now when I type. the whole table reloads with animation including the text I am typing. – Amogh Talpallikar Jun 12 '13 at 09:39
  • 2
    I found kCATransitionFade looks much better than kCATransitionFromBottom. – T.J. Jan 30 '14 at 17:46
  • Great solution, thank you. Minor quibble: For code readability, the method signature should really be `reloadDataAnimated:(BOOL)animated` – Carlos P Dec 16 '14 at 11:44
  • This is awesome, I've read about a dozen solutions and this is the best. If you want to slide the content up without existing content sliding up, use `kCATransitionMoveIn` and `kCATransitionFromTop`. – netwire Sep 02 '15 at 16:04
27

You can make a basic animation of reLoadData using:

// Reload table with a slight animation
[UIView transitionWithView:tableViewReference 
                  duration:0.5f 
                   options:UIViewAnimationOptionTransitionCrossDissolve 
                animations:^(void) {
    [tableViewReference reloadData];
} completion:NULL];
Vincent
  • 4,342
  • 1
  • 38
  • 37
  • On any other transition, the tableview data isn't reloaded until you begin scrolling. Any idea why? – Adam Carter Oct 31 '13 at 22:00
  • 1
    When you are updating the table not in the main flow, the table may not be automatically updated. In those cases you can use: [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; – Vincent Nov 01 '13 at 06:41
  • Does this go in the animation block? – Adam Carter Nov 01 '13 at 15:31
  • Nevermind, trial and error says it should be in the completion block of the transition. Thanks! :) – Adam Carter Nov 01 '13 at 15:34
14

You can simply call this lines when you want to reload the entire table with an animation:

NSRange range = NSMakeRange(0, [self numberOfSectionsInTableView:self.tableView]);
NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:range];
[self.tableView reloadSections:sections withRowAnimation:UITableViewRowAnimationFade];
barrast
  • 1,791
  • 1
  • 16
  • 27
  • Nice! Was looking for a clean solution this one is it for those the dont want call the brute reloadData .... – DogCoffee Apr 08 '15 at 08:25
9

You cannot animate reloadData. You will have to use the table view's insert..., delete..., move... and reloadRows... methods to make it animate.

This is pretty straightforward when using an NSFetchedResultsController. The documentation for NSFetchedResultsControllerDelegate contains a set of sample methods that you just have to adapt to your own code:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView beginUpdates];
}


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
    atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                            withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
                             withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
    atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
    newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch(type) {

        case NSFetchedResultsChangeInsert:
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[tableView cellForRowAtIndexPath:indexPath]
                  atIndexPath:indexPath];
            break;

        case NSFetchedResultsChangeMove:
            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                       withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
}
Ole Begemann
  • 135,006
  • 31
  • 278
  • 256
  • 1
    I'm sorry I did not mention I need reload table data after `NSFetchedResultsController` "refetch". I think, it could be done with some `CALayer` animation on whole `UITableView`... Something like duplicate table view layer, refetch, reload data, animate layer off... – user500 Sep 25 '11 at 20:10
5

I created a UITableView category method based on solution from this link.

It should reload all the table sections. You can play with UITableViewRowAnimation options for different animation effects.

- (void)reloadData:(BOOL)animated
{
    [self reloadData];

    if (animated)
    {
         [self reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.numberOfSections)] withRowAnimation:UITableViewRowAnimationBottom];
    }
}
Community
  • 1
  • 1
Despotovic
  • 1,807
  • 2
  • 20
  • 24
5
 typedef enum {
   UITableViewRowAnimationFade,
   UITableViewRowAnimationRight,
   UITableViewRowAnimationLeft,
   UITableViewRowAnimationTop,
   UITableViewRowAnimationBottom,
   UITableViewRowAnimationNone,
   UITableViewRowAnimationMiddle,
   UITableViewRowAnimationAutomatic = 100
} UITableViewRowAnimation;

and the method:

   [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
Robert Varga
  • 477
  • 1
  • 7
  • 15
1

You might want to use:

Objective-C

/* Animate the table view reload */
[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);

Animation options:

TransitionNone TransitionFlipFromLeft TransitionFlipFromRight TransitionCurlUp TransitionCurlDown TransitionCrossDissolve TransitionFlipFromTop TransitionFlipFromBottom

Reference

Community
  • 1
  • 1
Mohammad Zaid Pathan
  • 16,304
  • 7
  • 99
  • 130
1

Swift 5.1 version of answer @user500 (https://stackoverflow.com/users/620297/user500)

func reloadData(_ animated: Bool) {
    reloadData()
    guard animated else { return }
    let animation = CATransition()
    animation.type = .push
    animation.subtype = .fromBottom
    animation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
    animation.fillMode = .both
    animation.duration = 0.3
    layer.add(animation, forKey: "UITableViewReloadDataAnimationKey")
}
nurtugan
  • 79
  • 2
  • 2