2012-11-07 1 views
66

Nel mio progetto utilizzo UICollectionView per visualizzare una griglia di icone.UICollectionView modifica animata dei dati

L'utente è in grado di modificare l'ordine facendo clic su un controllo segmentato che chiama un recupero dai dati principali con diverso NSSortDescriptor.

La quantità di dati è sempre lo stesso, finendo in diverse sezioni/righe:

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

Il problema è che reloadData non anima la modifica, UICollectionView si apre appena con i nuovi dati .

Devo tenere traccia di quale indexPath è stata una cella prima e dopo la modifica e utilizzare [self.collectionView moveItemAtIndexPath: toIndexPath:] per eseguire l'animazione per la modifica oppure esiste un metodo migliore?

non ho avuto molto in collectionViews sottoclasse modo che qualsiasi aiuto sarà grande ...

Grazie, Bill.

+0

Hai provato avvolgere quella chiamata 'reloadData' in un blocco di animazione? – simon

risposta

58

reloadData non si anima, né lo fa in modo affidabile quando viene inserito in un blocco di animazione UIView. Si vuole essere in un blocco UICollecitonView performBatchUpdates, in modo da provare qualcosa di più simile:

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

sì, sembra funzionare, ma solo se si hanno numeri di sezione di salvataggio ... altrimenti sto ricevendo "numero non valido di sezioni." Il numero di sezioni contenute nella vista di raccolta dopo l'aggiornamento (10) deve essere uguale al numero delle sezioni contenute nella vista raccolta prima dell'aggiornamento (16) ". Devo inserire/eliminare manualmente le sezioni ... comunque accettate! Grazie. – Nimrod7

+1

Con "manualmente" intendi tramite le chiamate insertSections/moveSection: toSection/deleteSections di UICollectionView? O qualcos'altro? (scusa, finora il mio uso di UICollectionView ha avuto un numero statico di sezioni) – Stripes

+1

sì tramite quei metodi ... è un po 'complicato implementare il pensiero, devi ricordare i percorsi dell'indice prima e dopo l'aggiornamento, la figura che cosa è stata rimossa, o spostato ... – Nimrod7

130

Wrapping -reloadData in -performBatchUpdates: non sembra causare una vista collezione unica sezione per animare.

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

Tuttavia, questo codice funziona:

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

Nota dalla documentazione: Non devi chiamare il metodo di ricarica dei dati nel mezzo di blocchi di animazione in cui gli elementi vengono inseriti o eliminati. Inserimenti e cancellazioni causano automaticamente l'aggiornamento dei dati della tabella in modo appropriato. –

+0

penso che questa dovrebbe essere la risposta corretta. perché questo ha funzionato per me. Ho solo 1 sezione e questo non funziona la risposta corretta. –

+0

Non funziona se stai anche inserendo. Sovrascriverà l'animazione di ordinamento. –

2

Il testo di aiuto dice:

chiamare questo metodo per ricaricare tutti gli elementi nella vista raccolta. Questo fa sì che la vista raccolta scartini tutti gli elementi attualmente visibili e li visualizzi di nuovo. Per efficienza, la vista di raccolta mostra solo le celle e le viste supplementari che sono visibili . Se i dati della collezione si restringono in seguito al ricaricamento, la vista della collezione adatta di conseguenza gli scostamenti di scorrimento. Non dovresti chiamare questo metodo nel mezzo di blocchi di animazione in cui gli articoli sono inseriti o eliminati. Inserimenti e cancellazioni causano automaticamente l'aggiornamento dei dati della tabella in modo appropriato.

Penso che la parte chiave sia "fa sì che la vista di raccolta scartini tutti gli elementi attualmente visibili". Come animerà il movimento degli oggetti che ha scartato?

47

Questo è quello che ho fatto per animare ricarica di tutte le sezioni:

[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

Se si desidera un maggiore controllo e di controllo funzione personalizzabile this, contiene un spiegazione molto dettagliata dei vari modi di animare UICollectionViewCell.

4

Ricaricare l'intera vista dell'insieme all'interno di un blocco performBatchUpdates:completion: crea un'animazione glitch per il simulatore iOS 9. Se hai uno specifico UICollectionViewCell che vuoi eliminare, o se hai il percorso dell'indice, puoi chiamare deleteItemsAtIndexPaths: in quel blocco. Usando deleteItemsAtIndexPaths:, fa un'animazione liscia e piacevole.

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

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

Voglio solo menzionare una cosa che ha risolto il problema di crash nel mio caso, aggiornare l'origine dati (ad es.sezione/numero di elementi) prima di chiamare performUpdates sulla vista di raccolta. – ViruMax

-2

Per gli utenti Swift Questo viene portata di mano -

collectionView.performBatchUpdates({ 

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

      }, completion: nil) 
1

Per gli utenti Swift, se il vostro CollectionView ha una sola sezione:

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

Come visto in https://stackoverflow.com/a/42001389/4455570