user500
user500

Reputation: 4519

Animated reloadData on UITableView

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.

Upvotes: 33

Views: 32010

Answers (8)

nurtugan
nurtugan

Reputation: 79

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")
}

Upvotes: 1

Zaid Pathan
Zaid Pathan

Reputation: 16820

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

Upvotes: 1

barrast
barrast

Reputation: 1801

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];

Upvotes: 14

Robert Varga
Robert Varga

Reputation: 477

 typedef enum {
   UITableViewRowAnimationFade,
   UITableViewRowAnimationRight,
   UITableViewRowAnimationLeft,
   UITableViewRowAnimationTop,
   UITableViewRowAnimationBottom,
   UITableViewRowAnimationNone,
   UITableViewRowAnimationMiddle,
   UITableViewRowAnimationAutomatic = 100
} UITableViewRowAnimation;

and the method:

   [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

Upvotes: 5

Despotovic
Despotovic

Reputation: 1962

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];
    }
}

Upvotes: 5

Vincent
Vincent

Reputation: 4409

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];

Upvotes: 27

user500
user500

Reputation: 4519

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"];

    }
}

Upvotes: 83

Ole Begemann
Ole Begemann

Reputation: 135550

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];
}

Upvotes: 9

Related Questions