2012-11-07 13 views
66

In meinem Projekt verwende ich UICollectionView, um ein Raster von Symbolen anzuzeigen.UICollectionView animierte Daten ändern

Der Benutzer kann die Reihenfolge ändern, indem er auf ein segmentiertes Steuerelement klickt, das einen Abruf von Kerndaten mit unterschiedlichem NSSortDescriptor aufruft.

Die Datenmenge immer gleich ist, nur in verschiedenen Abschnitten/Zeilen enden:

- (IBAction)sortSegmentedControlChanged:(id)sender { 

    _fetchedResultsController = nil; 
    _fetchedResultsController = [self newFetchResultsControllerForSort]; 

    NSError *error; 
    if (![self.fetchedResultsController performFetch:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    } 

    [self.collectionView reloadData]; 
} 

Das Problem ist, dass reload nicht die Änderung nicht animieren, UICollectionView erscheint nur mit den neuen Daten .

Soll ich verfolgen, in welchem ​​IndexPfad eine Zelle vor und nach der Änderung war, und [self.collectionView moveItemAtIndexPath: toIndexPath:] verwenden, um die Animation für die Änderung durchzuführen, oder gibt es eine bessere Methode?

ich viel in Subklassifizieren collectionViews nicht so bekommen jede Hilfe wird groß sein ...

Danke, Bill.

+0

Haben Sie versucht, den 'reloadData'-Aufruf in einen Animationsblock umwandeln? – simon

Antwort

58

reloadData wird nicht animiert, auch nicht zuverlässig, wenn es in einen UIView-Animationsblock eingefügt wird. Er will in einem UICollecitonView performBatchUpdates Block sein, so versuchen, etwas mehr wie:

[self.collectionView performBatchUpdates:^{ 
    [self.collectionView reloadData]; 
} completion:^(BOOL finished) {}]; 
+4

yep, das scheint zu funktionieren, aber nur, wenn Sie Abschnittsnummern speichern ... sonst erhalte ich "ungültige Anzahl von Abschnitten. Die Anzahl der Abschnitte in der Sammlungsansicht nach dem Update (10) muss gleich der Zahl sein der Abschnitte, die in der Sammlungsansicht vor dem Update enthalten sind (16) ". Ich muss Abschnitte manuell einfügen/löschen ... trotzdem akzeptiert! Vielen Dank. – Nimrod7

+1

Mit "manuell", meinst du über UICollectionView's insertSections/moveSection: toSection/deleteSections Aufrufe? Oder etwas anderes? (Entschuldigung, bis jetzt hatte meine Verwendung von UICollectionView eine statische Anzahl von Abschnitten) – Stripes

+1

ja über diese Methoden ... es ist ein bisschen knifflig zu implementieren, denken Sie daran, die Indexpfade vor und nach dem Update, die Figur, was entfernt eingefügt, oder verschoben ... – Nimrod7

130

Wrapping -reloadData in -performBatchUpdates: scheint nicht einen Schnitt Sammlung Ansicht zu verursachen zu animieren.

[self.collectionView performBatchUpdates:^{ 
    [self.collectionView reloadData]; 
} completion:nil]; 

jedoch dieser Code funktioniert:

[self.collectionView performBatchUpdates:^{ 
    [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]]; 
} completion:nil]; 
+8

Hinweis aus der Dokumentation: Sie sollten die Methode reload data nicht inmitten von Animationsblöcken aufrufen, in die Elemente eingefügt oder gelöscht werden. Durch Einfügen und Löschen werden die Daten der Tabelle automatisch entsprechend aktualisiert. –

+0

Ich denke, das sollte die richtige Antwort sein. weil das für mich funktioniert hat. Ich habe nur 1 Abschnitt und das funktioniert nicht die richtige Antwort. –

+0

Funktioniert nicht, wenn Sie auch einfügen. Wird die Sortieranimation überschreiben. –

2

Der Hilfetext sagt:

Rufen Sie diese Methode alle Elemente in der Sammlung Ansicht neu zu laden. Dadurch werden in der Sammlungsansicht alle derzeit sichtbaren Elemente verworfen und erneut angezeigt. Aus Gründen der Effizienz zeigt die Sammlungsansicht nur Zellen und zusätzliche Ansichten an, die sichtbar sind. Wenn die Sammlungsdaten als Ergebnis des erneuten Ladens verkleinert werden, passt die Sammlungsansicht die Scroll-Offsets entsprechend an. Sie sollten diese Methode nicht in der Mitte von Animationsblöcken aufrufen, in denen Elemente eingefügt oder gelöscht werden. Durch Einfügen und Löschen werden die Daten der Tabelle automatisch entsprechend aktualisiert.

Ich denke, der Schlüssel Teil ist "bewirkt, dass die Sammlung Ansicht alle derzeit sichtbaren Elemente verwerfen". Wie wird es die Bewegung von Gegenständen animieren, die es weggeworfen hat?

47

Dies ist, was ich reload aller Teile zu animieren tat

[self.collectionView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.collectionView.numberOfSections)]]; 

Swift 3

let range = Range(uncheckedBounds: (0, collectionView.numberOfSections)) 
let indexSet = IndexSet(integersIn: range) 
collectionView.reloadSections(indexSet) 
2

Wenn Sie mehr Kontrolle und anpassbaren Funktion überprüfen möchten this, es enthält ein sehr detaillierte Erklärung der verschiedenen Arten von UICollectionViewCell Animationen.

4

Das Nachladen der gesamten Kollektionsansicht in einem performBatchUpdates:completion: Block macht eine glitschige Animation für mich auf iOS 9 Simulator. Wenn Sie einen bestimmten UICollectionViewCell haben, den Sie löschen möchten, oder wenn Sie seinen Indexpfad haben, können Sie deleteItemsAtIndexPaths: in diesem Block aufrufen. Mit deleteItemsAtIndexPaths: macht es eine glatte und nette Animation.

UICollectionViewCell* cellToDelete = /* ... */; 
NSIndexPath* indexPathToDelete = /* ... */; 

[self.collectionView performBatchUpdates:^{ 
    [self.collectionView deleteItemsAtIndexPaths:@[[self.collectionView indexPathForCell:cell]]]; 
    // or... 
    [self.collectionView deleteItemsAtIndexPaths:@[indexPath]]; 
} completion:nil]; 
+1

Ich möchte nur eine Sache erwähnen, die Crash-Problem in meinem Fall gelöst hat, aktualisieren Sie die Datenquelle (d.Abschnitt/item count) vor dem Aufruf von performUpdates in der Sammlungsansicht. – ViruMax

-2

Für schnellen Anwender kommt dieses handliche -

collectionView.performBatchUpdates({ 

      self.collectionView.reloadSections(NSIndexSet(index: index)) 

      }, completion: nil) 
1

Für Swift Benutzer, wenn Ihre Kollektion nur einen Abschnitt hat:

self.collectionView.performBatchUpdates({ 
        let indexSet = IndexSet(integersIn: 0...0) 
        self.collectionView.reloadSections(indexSet) 
       }, completion: nil) 

Wie auf https://stackoverflow.com/a/42001389/4455570 gesehen

Verwandte Themen