7

I have a UITableViewCell that expands and adds a label on click.

Logic:

I added a label in cellForRowAtIndexPath to the selected cell, and in didSelectRow... I reloaded the tableView. In heightForRow... the selected cell expands. Hope you get the picture.

In didSelectRow... I have to reloadData, and not begin/end update. What I want to do is reloadData and have it animate. I can do like this:

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

So that does a cross dissolve of the cells that is changing. What I want is UITableViewRowAnimationTop, but apparently that is not possible in the transition options. Is there a way to reloadData and use UITableViewRowAnimationTop?

  • Calling `reloadData` destroys all cells currently in the table view and rebuilds everything back from scratch. You may be looking for a different method if this is not the behaviour that you desire. – Ian MacDonald Feb 05 '15 at 19:52
  • So there is no way of using `UITableViewRowAnimationTop` with reloadData? –  Feb 05 '15 at 19:53
  • Did you try using [beginUpdates](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITableView_Class/index.html#//apple_ref/occ/instm/UITableView/beginUpdates) and an update block? – matt Feb 05 '15 at 19:55
  • Do you mean [tableView beginUpdates]; [tableView EndUpdates]? –  Feb 05 '15 at 19:58
  • A little late to this party – from your description you want the cell to grow and fit in the new label. A contemporary approach for this is to use "self sizing cells" with auto layout set up appropriately. If you're using self sizing cells then you can simply do: `tableView.beginUpdates(); tableView.endUpdates()` and cells will expand of contract as appropriate to match their current content. No reloads are required (unless the table's valid index path set has changed). You can find more details about an approach to this [here](https://stackoverflow.com/a/2063776/2547229). – Benjohn Nov 23 '17 at 08:41

5 Answers5

9

A much simpler solution that doesn't require CoreAnimation.

Swift 3:

UIView.transition(with: self.view,
                  duration: 0.15,
                  options: [.curveEaseInOut, .transitionCrossDissolve],
                  animations: {
                      self.tableView.reloadRows(at: self.tableView.indexPathsForVisibleRows!, with: .none)
}, completion: nil)
brandonscript
  • 68,675
  • 32
  • 163
  • 220
8

[UITablewView reloadData:] is not animatable. However, you may want to try reloading tableView by reloading all sections with animation.

NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [tableView numberOfSections])];

[self.tableView reloadSections:sections withRowAnimation:UITableViewRowAnimationAutomatic];

OK, I lied. It may be animatable but it requires much knowledge about how QuartzCore Framework operates on UI components.

@import QuartzCore;

[self.tableView reloadData];

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

[self.tableView.layer addAnimation:transition forKey:@"UITableViewReloadDataAnimationKey"];
Ozgur Vatansever
  • 49,246
  • 17
  • 84
  • 119
  • There isn't `animation` a xcodes intelligent inspector. –  Feb 06 '15 at 07:37
  • I didn't understand what you meant. `CATransition` has a class method named `transition`. Are you sure you are not writing `CATransaction`? – Ozgur Vatansever Feb 06 '15 at 07:41
  • You're right, I was using `CATransaction`. I just tried it, and what happens is, the whole tableView goes down then back up, and the table doesn't even reload? –  Feb 06 '15 at 17:54
3

Swift 4 solution with QuartzCore

import QuartzCore

tableView.reloadData()

let transition = CATransition()
transition.type = kCATransitionPush
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.fillMode = kCAFillModeForwards
transition.duration = 0.6
transition.subtype = kCATransitionFromBottom
    
tableView.layer.add(transition, forKey: "UITableViewReloadDataAnimationKey")

Swift 5

tableView.reloadData()
let transition = CATransition()
transition.type = .push
transition.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
transition.fillMode = .forwards
transition.duration = 0.6
transition.subtype = .fromBottom
koen
  • 5,383
  • 7
  • 50
  • 89
kubacizek
  • 578
  • 4
  • 9
1

Or this:

    NSIndexSet *sections = [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [self numberOfSectionsInTableView: self.tableView])];
    [self.tableView reloadSections: sections withRowAnimation: UITableViewRowAnimationTop];

Personally, I think UITableViewRowAnimationFade looks much better tho.

Simon Tillson
  • 3,609
  • 1
  • 15
  • 23
0

This UITableView extension works for Swift 4:

extension UITableView {
  func reloadDataWithAnimation(duration: TimeInterval, options: UIViewAnimationOptions) {
    UIView.animate(withDuration: duration, delay: 0.0, options: options, animations: { self.alpha = 0 }, completion: nil)
    self.reloadData()
    UIView.animate(withDuration: duration, delay: 0.0, options: options, animations: { self.alpha = 1 }, completion: nil)
  }
}

Usage:

tableView.reloadDataWithAnimation(duration: 1.0, options: .curveLinear)
budiDino
  • 13,044
  • 8
  • 95
  • 91
fivewood
  • 391
  • 4
  • 11
  • This approach uses `reloadData()` so that it allows animation of updates to the tableView structure (not just row or section insertions, deletions or updates but also refetching or otherwise changing the data source). – fivewood Jan 13 '18 at 18:12