UICollectionView animuj zmianę danych

83

W moim projekcie używam UICollectionView do wyświetlania siatki ikon.

Użytkownik może zmienić kolejność, klikając podzieloną na segmenty kontrolkę, która wywołuje pobieranie z danych podstawowych za pomocą innego NSSortDescriptor.

Ilość danych jest zawsze taka sama, po prostu znajdują się w różnych sekcjach / wierszach:

- (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];
}

Problem polega na tym, że reloadData nie animuje zmiany, UICollectionView po prostu wyskakuje z nowymi danymi.

Czy powinienem śledzić, w którym indexPath komórka była przed i po zmianie, i użyć [self.collectionView moveItemAtIndexPath: toIndexPath:], aby wykonać animację zmiany, czy jest lepsza metoda?

Nie interesowałem się zbytnio podklasą collectionViews, więc każda pomoc będzie świetna ...

Dzięki, Bill.

Nimrod7
źródło
Czy próbowałeś opakować to reloadDatawywołanie w blok animacji?
simon

Odpowiedzi:

72

reloadData nie animuje, ani nie robi tego niezawodnie po umieszczeniu w bloku animacji UIView. Chce być w bloku performBatchUpdates UICollecitonView, więc spróbuj czegoś więcej na przykład:

[self.collectionView performBatchUpdates:^{
    [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:^(BOOL finished) {
    // do something on completion 
}];
Paski
źródło
5
tak, to wydaje się działać, ale tylko jeśli masz zapisane numery sekcji ... w przeciwnym razie otrzymuję „nieprawidłową liczbę sekcji. Liczba sekcji zawartych w widoku kolekcji po aktualizacji (10) musi być równa liczbie sekcje zawarte w widoku kolekcji przed aktualizacją (16) ”. Muszę ręcznie wstawiać / usuwać sekcje ... i tak zaakceptowano! Dzięki.
Nimrod7
1
Czy przez „ręcznie” masz na myśli wywołania insertSections / moveSection: toSection / deleteSections UICollectionView? Albo coś innego? (przepraszam, do tej pory moje użycie UICollectionView miało stałą liczbę sekcji)
Stripes
1
tak, za pomocą tych metod ... to trochę trudne do zaimplementowania myśli, musisz zapamiętać ścieżki indeksu przed i po aktualizacji, rysunek, który usunięto, wstawiono lub przeniesiono ...
Nimrod7
12
To nie zadziałało w moim widoku kolekcji z jedną sekcją. Nie otrzymałem błędów, ale nie było animacji. Zastępowanie -reloadSections:sprawia, że ​​to działa.
paulmelnikow
9
Ta odpowiedź nie jest poprawna, ponieważ w moim przypadku umieszczenie reloadData w performBatchUpdates spowoduje awarię mojej aplikacji i powiedzenie, że liczba komórek nie jest taka sama przed i po. użycie reloadSections rozwiązało mój problem. Dokument Apple wskazuje również, że nie należy wywoływać funkcji reloadData w bloku animacji
Wingzero
145

Zawijanie -reloadData w -performBatchUpdates:nie wydaje się, aby spowodować jeden punkt zbiórki widok animować.

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

Jednak ten kod działa:

[self.collectionView performBatchUpdates:^{
    [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:nil];
paulmelnikow
źródło
9
Uwaga z dokumentacji: Nie należy wywoływać metody przeładowania danych w środku bloków animacji, w których elementy są wstawiane lub usuwane. Wstawienia i usunięcia automatycznie powodują, że dane tabeli są odpowiednio aktualizowane.
Raphael Oliveira
myślę, że to powinna być prawidłowa odpowiedź. ponieważ to zadziałało dla mnie. mam tylko 1 sekcję i to nie działa poprawnie.
Mahesh Agrawal
Nie działa, jeśli również wstawiasz. Zastąpi animację sortowania.
Andres Canella
3
Warto zauważyć, że nie potrzebujesz self.collectionView performBatchUpdateszawiniętego połączenia, reloadSectionsaby uzyskać animację. W rzeczywistości performBatchUpdateswywołanie może w niektórych przypadkach powodować nieumyślne migotanie / problemy ze zmianą rozmiaru komórki.
Paul Popiel
1
Lub po prostu [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]]; reloadSectionsw widoku kolekcji lub widoku tabeli zrobi to z animacją.
bauerMusic
67

Oto, co zrobiłem, aby ożywić ponowne załadowanie WSZYSTKICH SEKCJI:

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

Szybki 3

let range = Range(uncheckedBounds: (0, collectionView.numberOfSections))
let indexSet = IndexSet(integersIn: range)
collectionView.reloadSections(indexSet)
Yariv Nissim
źródło
8

W przypadku użytkowników Swift, jeśli widok kolekcji ma tylko jedną sekcję:

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

Jak widać na https://stackoverflow.com/a/42001389/4455570

Gabriel Wamunyu
źródło
3

Ponowne załadowanie całego widoku kolekcji wewnątrz performBatchUpdates:completion:bloku powoduje wyświetlenie dla mnie animacji na symulatorze iOS 9. Jeśli masz konkretny element, UICollectionViewCellktóry chcesz usunąć, lub jeśli masz jego ścieżkę indeksu, możesz wywołać deleteItemsAtIndexPaths:w tym bloku. Używając deleteItemsAtIndexPaths:, tworzy płynną i ładną animację.

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

[self.collectionView performBatchUpdates:^{
    [self.collectionView deleteItemsAtIndexPaths:@[[self.collectionView indexPathForCell:cell]]];
    // or...
    [self.collectionView deleteItemsAtIndexPaths:@[indexPath]];
} completion:nil];
Nemezys
źródło
1
Chcę tylko wspomnieć o rzeczy, która rozwiązała problem z awarią w moim przypadku, zaktualizuj źródło danych (tj. Liczbę sekcji / pozycji) przed wywołaniem performUpdates w widoku kolekcji.
ViruMax
Animacja pochodzi z innych operacji; istnieje i nigdy nie było W ŻADNYCH OKOLICZNOŚCIACH animacja reloadData. insertItems wstawia w kolejności rosnącej i jest wykonywany PO aktualizacjach; deleteItems jest odwrotnie.
James Bush
1

Tekst pomocy mówi:

Wywołaj tę metodę, aby ponownie załadować wszystkie elementy w widoku kolekcji. Powoduje to, że widok kolekcji odrzuca wszystkie aktualnie widoczne elementy i wyświetla je ponownie. Aby zwiększyć wydajność, widok kolekcji wyświetla tylko te komórki i dodatkowe widoki, które są widoczne. Jeśli dane kolekcji zmniejszają się w wyniku ponownego wczytywania, widok kolekcji odpowiednio dostosowuje przesunięcia przewijania. Nie powinieneś wywoływać tej metody w środku bloków animacji, w których elementy są wstawiane lub usuwane. Wstawienia i usunięcia automatycznie powodują, że dane tabeli są odpowiednio aktualizowane.

Myślę, że kluczową częścią jest „powoduje, że widok kolekcji odrzuca wszystkie aktualnie widoczne elementy”. Jak ma ożywić ruch odrzuconych przedmiotów?

Victor Engel
źródło
Dokładnie tak nie jest. reloadData to podwójna operacja bez animacji; jest to najpierw operacja usuwania, a następnie operacja wstawiania.
James Bush