43

I am reloading a tableView section using this code -

self.tableView.beginUpdates()
self.tableView.reloadSections(NSIndexSet(index: 1), withRowAnimation: UITableViewRowAnimation.None)
self.tableView.endUpdates()

Still the rows replacement is animated and the table view scrolls to the top.

How can I make sure that no animation will be applied to the section reload + prevent the table view from scrolling.

mfaani
  • 33,269
  • 19
  • 164
  • 293
shannoga
  • 19,649
  • 20
  • 104
  • 169

8 Answers8

71

To prevent scrolling and animation, do this:

UIView.performWithoutAnimation { 
    let loc = tableView.contentOffset
    tableView.reloadRows(at: [indexPath], with: .none)
    tableView.contentOffset = loc
}
shim
  • 9,289
  • 12
  • 69
  • 108
n13
  • 6,843
  • 53
  • 40
  • 1
    Works for me on iOS9. Amazing technique! Thx – Mikael Sep 22 '17 at 14:42
  • Docs says .none use the default animation, but with this code updated rows aren't animated. Thanks. – user3057944 Jan 25 '18 at 15:50
  • 1
    I think it should be `tableView.setContentOffset(loc, animated: false)` instead of `tableView.contentOffset = loc` – Anjan Biswas Apr 05 '18 at 18:15
  • 2
    Worked fo me on Swift 4.1 – Ravi Aug 25 '18 at 10:37
  • 1
    the `contentOffset` hack wasn't necessary for me. [This answer here](https://stackoverflow.com/a/46591965/1032372) was sufficient. – shim Nov 23 '18 at 16:59
  • ^ @shim thanks for the info - it might have changed since 2016 and maybe content offset is no longer necessary. There might be edge cases where it matters though. – n13 May 16 '19 at 15:19
61

Swift 4:

Actually, the best way to prevent crazy animation during scrolling or expand/collapse cells is:

UIView.performWithoutAnimation {
       self.tableView.reloadRows(at: [indexPath], with: .none)
}
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
  • 1
    That actually worked and not only on Swift 4 but in 3.2 as well. This API appears to be available since iOS 7.0 Thank you! – iPav Oct 27 '17 at 00:01
  • 1
    You can skip `self` in `tableView.reloadRows` call to make code little cleaner. – Kamil Harasimowicz Feb 15 '18 at 15:52
  • 4
    @KamilHarasimowicz: You can not remove self since UIView.performWithoutAnimation is a closure. You need to add self inside it – Anand Jul 09 '19 at 09:25
50

Try this:

UIView.setAnimationsEnabled(false)
self.tableView.beginUpdates()
self.tableView.reloadSections(NSIndexSet(index: 1) as IndexSet, with: UITableViewRowAnimation.none)
self.tableView.endUpdates()
shim
  • 9,289
  • 12
  • 69
  • 108
Abhinav
  • 37,684
  • 43
  • 191
  • 309
11

Swift 5

UIView.performWithoutAnimation {
   self.tableView.reloadRows(at: [indexPath], with: .none)
  }
Usama Ali
  • 129
  • 1
  • 7
8

Neither of given answers worked for me. Here's the solution I found, hope it would be useful to someone

Swift 4:

let lastScrollOffset = tableView.contentOffset

tableView.beginUpdates()
tableView.reloadSections(IndexSet(integer: 1), with: .none)
tableView.endUpdates()

tableView.layer.removeAllAnimations()
tableView.setContentOffset(lastScrollOffset, animated: false)
Baradasy
  • 129
  • 2
  • 7
5

Add one line more to this method in viewDidLoad

self.tableView.remembersLastFocusedIndexPath = true

Add this code where you want refresh after updation

UIView.setAnimationsEnabled(false)
    self.tableView.beginUpdates()
    self.tableView.reloadSections(NSIndexSet(index: 1) as IndexSet, with: UITableViewRowAnimation.none)
    self.tableView.endUpdates()
franiis
  • 1,378
  • 1
  • 18
  • 33
Gurpreet Singh
  • 803
  • 9
  • 16
5

Objective-C:

[UIView setAnimationsEnabled:NO];
   [[self tableView]beginUpdates];
   [self.tableView reloadSections:[[NSIndexSet alloc] initWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
   [[self tableView]endUpdates];

But I think the following code is more useful and better.

[UIView performWithoutAnimation:^{     
                [[self tableView]beginUpdates];
                [self.tableView reloadSections:[[NSIndexSet alloc] initWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
                [[self tableView]endUpdates];
            }];
Okan
  • 410
  • 4
  • 10
0

I've had this problem too. It seems to stem from putting an IndexPath inside .reloadSections instead of a IndexSet as it requests. Which is why it seems to work with .reloadRows with out issue:

tableView.reloadRows(at: [IndexPath], with: UITableView.RowAnimation)

tableView.reloadSections(IndexSet, with: UITableView.RowAnimation)

Just wrap the section you want to reload as an IndexSet:

tableView.reloadSections(IndexSet(integer: sectionInt), with: .none)
StonedStudio
  • 507
  • 3
  • 20