Vermeiden Sie die Animation von UICollectionView nach reloadItemsAtIndexPaths

86

UICollectionView animiert Elemente, nachdem reloadItemsAtIndexPaths aufgerufen wurde (Animation verblassen).

Gibt es eine Möglichkeit, diese Animation zu vermeiden?

iOS 6

Marcin
quelle

Antworten:

160

Sie können dies auch versuchen:

UICollectionView *collectionView;

...

[UIView setAnimationsEnabled:NO];

[collectionView performBatchUpdates:^{
    [collectionView reloadItemsAtIndexPaths:indexPaths];
} completion:^(BOOL finished) {
    [UIView setAnimationsEnabled:YES];
}];

Bearbeiten:

Ich habe auch festgestellt, dass performBatchUpdatesbeim Umschließen eines UIView-Animationsblocks die UIView-Animation anstelle der Standardanimation verwendet wird, sodass Sie die Animationsdauer wie folgt auf 0 setzen können:

[UIView animateWithDuration:0 animations:^{
    [collectionView performBatchUpdates:^{
        [collectionView reloadItemsAtIndexPaths:indexPaths];
    } completion:nil];
}];

Dies ist besonders cool, wenn Sie beim Einfügen und Löschen federnde iOS 7-Animationen verwenden möchten!

Sam
quelle
1
Danke dir. Dies war sehr hilfreich beim Hinzufügen von Stoppuhr-Timern zu uicollectionview-Zellen.
Hatunike
Brillant! Ich habe dies mit insertCells und mit der Tastatur nach oben verwendet, um die collectionView nach dem Einfügen der Zelle auf einen neuen Versatz zu animieren.
David H
5
Wie Peter sagt, stört dies andere Animationen. Stattdessen sollten Sie [UIView setAnimationsEnabled: YES] außerhalb des Abschlussblocks aufrufen. Auf diese Weise verhindern Sie nur diese 1 Animation.
Adlai Holler
2
Ich habe eine alternative Methode hinzugefügt, die genau das Gleiche tut.
Sam
1
performBatchUpdatesInnen einwickeln animateWithDurationist genial! Danke für den Tipp!
Robert
225

Es ist erwähnenswert, dass Sie die neue UIViewMethode verwenden können, wenn Sie auf iOS 7 und höher abzielen performWithoutAnimation:. Ich vermute, dass dies unter der Haube ähnlich funktioniert wie die anderen Antworten hier (vorübergehende Deaktivierung von UIViewAnimationen / Core-Animationsaktionen), aber die Syntax ist nett und sauber.

Also gerade für diese Frage ...

Ziel c:

[UIView performWithoutAnimation:^{
    [self.collectionView reloadItemsAtIndexPaths:indexPaths];
}];


Schnell:

UIView.performWithoutAnimation {
    self.collectionView.reloadItemsAtIndexPaths(indexPaths)
}


Natürlich kann dieses Prinzip auf jede Situation angewendet werden, in der Sie sicherstellen möchten, dass eine Änderung nicht animiert wird.

Stuart
quelle
3
Dies funktionierte besser als die akzeptierte Antwort für mich unter iOS 7+.
Philippe Sabourin
Es deaktiviert alle Animationen nicht nur für die Sammlungsansicht
user2159978
10
@ user2159978 Das ist richtig; Alle Antworten hier deaktivieren vorübergehend UIView-Animationen. Die Animationen sind nur für Aktionen deaktiviert, die innerhalb des übergebenen Blocks initiiert wurden, in diesem Fall nur für das Neuladen der Sammlungsansicht. Es ist eine absolut gültige Antwort auf die gestellte Frage, daher denke ich nicht, dass es eine Abwertung verdient.
Stuart
Unglaubliche Lösung. Die Verwendung dieser Option anstelle von animateWithDuration: 0 verhindert einen schnellen, aber sichtbaren Layoutfehler, wenn Zellen mit Sammlungsansicht in der Größe ohne itemSize verwendet werden
Ethan Gill,
18

UICollectionView animiert Elemente, nachdem reloadItemsAtIndexPaths aufgerufen wurde (Animation verblassen).

Gibt es eine Möglichkeit, diese Animation zu vermeiden?

iOS 6

Ich gehe davon aus, dass Sie ein FlowLayout verwenden. Versuchen Sie Folgendes, da Sie versuchen, die Überblendungsanimation zu entfernen:

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
    }

}

Dies ist eine sehr alte Frage, daher zielen Sie wahrscheinlich nicht mehr auf iOS 6 ab. Ich habe persönlich an tvOS 11 gearbeitet und hatte die gleiche Frage. Dies ist also für alle da, die das gleiche Problem haben.

Matt Mc
quelle
1
Es gab 3 oder 4 Kommentare zu dieser Antwort mit dem Effekt "Wow, das funktioniert wirklich gut!" Jemand hat beschlossen, die Kommentare zu entfernen. Ich denke, tatsächlich ist dies die moderne und nicht hackige Art, dies zu erreichen, und diese Kommentare waren eine Anerkennung dafür.
Matt Mc
8

Ich habe eine Kategorie auf UICollectionView geschrieben , um genau das zu tun. Der Trick besteht darin, alle Animationen beim Neuladen zu deaktivieren:

if (!animated) {
    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
}

[self reloadItemsAtIndexPaths:indexPaths];

if (!animated) {
    [CATransaction commit];
}
Giorgio Calderolla
quelle
Ich bekomme auch die Antwort von Apple, dass dies keine Animation machen sollte, wenn ja, ist es ein Fehler. Ich weiß nicht, ob ich etwas falsch mache oder ob es ein Fehler ist.
Marcin
2
Sie können dies auch nur CATransaction.setDisableActions(true)als Abkürzung tun .
CIFilter
5

Hier ist eine Swift 3 Version performBatchUpdatesohne Animation zu einem UICollectionView. Ich fand, dass dies für mich besser funktioniert, als collectionView.reloadData()weil es das Austauschen von Zellen beim Einfügen von Datensätzen verringert.

func appendCollectionView(numberOfItems count: Int){

        // calculate indexes for the items to be added
        let firstIndex = dataItems.count - count
        let lastIndex = dataItems.count - 1

        var indexPaths = [IndexPath]()
        for index in firstIndex...lastIndex {
            let indexPath = IndexPath(item: index, section: 0)
            indexPaths.append(indexPath)
        }

   UIView.performWithoutAnimation {

        self.collectionView.performBatchUpdates({ () -> Void in
            self.collectionView.insertItems(at: indexPaths)
        }, completion: { (finished) -> Void in

        })
    }
}
Markhorrocks
quelle
4
extension UICollectionView {
    func reloadWithoutAnimation(){
        CATransaction.begin()
        CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
        self.reloadData()
        CATransaction.commit()
    }
}
Amjad Tubasi
quelle
Dies ist schnelle 3 Syntax
Amjad Tubasi
Dies funktionierte gut, sogar besser als UIView.performWithoutAnimation
Lance Samaria
2
- (void)reloadCollectionViewAnimated:(BOOL)animated  {

    if (animated) {
        [self.collectionView performBatchUpdates:^{
            [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
        } completion:^(BOOL finished) {

        }];
    } else {
        [CATransaction begin];
        [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
        [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
        [CATransaction commit];
    }

}
Peter Lapisu
quelle
1

Um meine $ 0,02 hinzuzufügen, habe ich beide Versionen der ausgewählten Antwort ausprobiert, und die ursprüngliche Methode hat für meine Zwecke besser funktioniert. Ich arbeite an einer unendlichen Bildlauf-Kalenderansicht, mit der ein Benutzer den Kalender zu einer bestimmten Woche eingeben und dann hin und her wischen und einzelne Tage zum Filtern einer Liste auswählen kann.

In meiner Implementierung muss die Anzahl der Daten, die die Kalenderansicht darstellen, relativ klein gehalten werden, um die Leistung auf älteren Geräten zu gewährleisten. Dies bedeutet, dass Daten im Wert von etwa 5 Wochen gespeichert werden, wobei sich der Benutzer in der 3. Woche in der Mitte befindet. Das Problem bei der Verwendung des zweiten Ansatzes besteht darin, dass Sie in einem zweiten Schritt die Sammlungsansicht ohne Animation zurück in die Mitte scrollen müssen, was aus irgendeinem Grund bei der blockierten Basisanimation zu einem sehr gezackten Erscheinungsbild führt.

Mein Code:

[UIView setAnimationsEnabled:NO];
[self.collectionView performBatchUpdates:^{
    [self.collectionView deleteItemsAtIndexPaths:indexPathDeleteArray];
    [self.collectionView insertItemsAtIndexPaths:indexPathAddArray];

} completion:NULL];
[UIView setAnimationsEnabled:YES];

NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:14 inSection:0];
[self.collectionView scrollToItemAtIndexPath:newIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];
Matt S.
quelle