Avoid animation of UICollectionView after reloadItemsAtIndexPaths
Solution 1
It's worth noting that if you're targeting iOS 7 and above, you can use the new UIView
method performWithoutAnimation:
. I suspect that under the hood this is doing much the same as the other answers here (temporarily disabling UIView
animations / Core Animation actions), but the syntax is nice and clean.
So for this question in particular...
Objective-C:
[UIView performWithoutAnimation:^{
[self.collectionView reloadItemsAtIndexPaths:indexPaths];
}];
Swift:
UIView.performWithoutAnimation {
self.collectionView.reloadItemsAtIndexPaths(indexPaths)
}
Of course this principle can be applied for any situation that you want to ensure a change is not animated.
Solution 2
You could also try this:
UICollectionView *collectionView;
...
[UIView setAnimationsEnabled:NO];
[collectionView performBatchUpdates:^{
[collectionView reloadItemsAtIndexPaths:indexPaths];
} completion:^(BOOL finished) {
[UIView setAnimationsEnabled:YES];
}];
Edit:
I have also found that if you wrap performBatchUpdates
in a UIView animation block, the UIView animation is used instead of the default animation, so you can just set the animation duration to 0, like so:
[UIView animateWithDuration:0 animations:^{
[collectionView performBatchUpdates:^{
[collectionView reloadItemsAtIndexPaths:indexPaths];
} completion:nil];
}];
This is extra cool if you want to use iOS 7 springy animations during inserts and deletes!
Solution 3
UICollectionView animate items after reloadItemsAtIndexPaths is called (fade animation).
Is there a way to avoid this animation?
iOS 6
I assume you're using a FlowLayout. Since you're trying to get rid of the fade animation, try this:
import UIKit
class NoFadeFlowLayout: UICollectionViewFlowLayout {
override func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attrs = super.initialLayoutAttributesForAppearingItem(at: itemIndexPath)
attrs?.alpha = 1.0
return attrs
}
override func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attrs = super.finalLayoutAttributesForDisappearingItem(at: itemIndexPath)
attrs?.alpha = 1.0
return attrs
}
}
This is a very old question, so you're probably not targeting iOS 6 anymore. I was personally working on tvOS 11 and had the same question, so this is here for anyone who comes along with the same problem.
Solution 4
I wrote a category on UICollectionView to do just that. The trick is to disable all animations while reloading:
if (!animated) {
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
}
[self reloadItemsAtIndexPaths:indexPaths];
if (!animated) {
[CATransaction commit];
}
Solution 5
extension UICollectionView {
func reloadWithoutAnimation(){
CATransaction.begin()
CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
self.reloadData()
CATransaction.commit()
}
}
Marcin
Passionate developer. iOS. https://github.com/krzyzanowskim
Updated on July 08, 2022Comments
-
Marcin almost 2 years
UICollectionView animate items after reloadItemsAtIndexPaths is called (fade animation).
Is there a way to avoid this animation?
iOS 6
-
Marcin over 11 yearsI also get response from Apple that this should not do any animation, if so it's a bug. I don't know if I'm doing something wrong or it's a bug.
-
hatunike about 11 yearsThank you. This was very helpful in adding stopwatch timers to uicollectionview cells.
-
David H over 10 yearsBrilliant! I used this with insertCells, and with the keyboard up, to animate the collectionView to a new offset after the cell was inserted.
-
Peter Lapisu over 10 yearsconflicts with other animations :/
-
Adlai Holler over 10 yearsAs Peter says, this interferes with other animations. Instead, you should call [UIView setAnimationsEnabled:YES] outside of the completion block. That way you only prevent that 1 animation.
-
Sam about 10 yearsI added an alternative method, which does exactly the same thing.
-
Robert over 9 yearsWrapping
performBatchUpdates
insideanimateWithDuration
is brilliant! Thanks for the tip! -
Philippe Sabourin over 9 yearsThis worked better than the accepted answer for me on iOS 7+.
-
user2159978 over 9 yearsWARNING. This method DOESN'T WORK PROPERLY!!! Try to scroll while this method is executed. At least in my case when I should reload layout too it breaks content size of collection view
-
user2159978 over 9 yearsIt disables all the animations not only for collection view
-
Stuart over 9 years@user2159978 That's correct; all the answers here temporarily disable UIView animations. The animations are only disabled for actions initiated from within the passed-in block, in this case just the collection view's reload. It is a perfectly valid answer to the question being asked, so I don't think it deserves a down vote.
-
BollMose over 8 yearsI don't know why but it's perfectly fix my flashing issue with UIView animateWithDuration:0 animations. Thank you very much.
-
Magoo about 8 yearsSecond one is much safer! :)
-
Just a coder almost 8 yearsVisually, the second method does not work as well as the first method.
-
Amjad Tubasi over 7 yearsthis is swift 3 syntax
-
CIFilter about 7 yearsYou can also just do
CATransaction.setDisableActions(true)
as a shorthand for this. -
Ethan Gill over 6 yearsIncredible solution. Using this instead of animateWithDuration:0 prevents a quick but visible layout glitch when using self-sizing collection view cells with no itemSize
-
Matt Mc almost 5 yearsThere were 3 or 4 comments on this answer to the effect of "Wow this works really well!" Someone decided to remove the comments. I think, factually, this is the modern and non-hacky way of accomplishing this, and those comments were a recognition of this.
-
Lance Samaria almost 4 yearsthis worked good, even better than UIView.performWithoutAnimation
-
Maray97 over 3 yearsThis solution doesn't work anymore on iOS 14, inside this block I use reloadData, but with iOS 13 it worked