Durata dell'animazione di riga UITableView e callback di completamento


98

Esiste un modo per specificare la durata delle animazioni delle righe UITableView o per ottenere una richiamata al termine dell'animazione?

Quello che vorrei fare è far lampeggiare gli indicatori di scorrimento al termine dell'animazione. Fare il flash prima di allora non fa nulla. Finora la soluzione alternativa che ho è ritardare di mezzo secondo (che sembra essere la durata dell'animazione predefinita), ovvero:

[self.tableView insertRowsAtIndexPaths:newRows
                      withRowAnimation:UITableViewRowAnimationFade];
[self.tableView performSelector:@selector(flashScrollIndicators)
                     withObject:nil
                     afterDelay:0.5];

Non ci ho provato, ma forse questo potrebbe farlo, con un po 'di gestione del percorso dell'indice:- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
Kalle

Risposte:


3

Al giorno d'oggi se vuoi farlo c'è una nuova funzione a partire da iOS 11 :

- (void)performBatchUpdates:(void (^)(void))updates 
                 completion:(void (^)(BOOL finished))completion;

Nelle chiusure degli aggiornamenti si inserisce lo stesso codice della sezione beginUpdates () / endUpdates. E il completamento viene eseguito dopo tutte le animazioni.


Questo è fantastico. Non avevo notato questa aggiunta.
Daniel Dickison,

207

Mi sono appena imbattuto in questo. Ecco come farlo:

Obiettivo-C

[CATransaction begin];
[tableView beginUpdates];
[CATransaction setCompletionBlock: ^{
    // Code to be executed upon completion
}];
[tableView insertRowsAtIndexPaths: indexPaths
                 withRowAnimation: UITableViewRowAnimationAutomatic];
[tableView endUpdates];
[CATransaction commit];

Swift

CATransaction.begin()
tableView.beginUpdates()
CATransaction.setCompletionBlock {
    // Code to be executed upon completion
}
tableView.insertRowsAtIndexPaths(indexArray, withRowAnimation: .Top)
tableView.endUpdates()
CATransaction.commit()

2
Ancora una volta, funziona perfettamente qui. iOS6 e tutti. Si tratta di un meccanismo corretto supportato dall'SDK per l'override delle proprietà nelle animazioni predefinite. Forse hai animazioni aggiuntive e di lunga durata nella tua CATransaction? Si annidano, sai.
karwag

1
Funziona alla grande per me in iOS6. Grazie per quello!
Aron

5
setAnimationDurationnon sembra influenzare la durata di inserimento / eliminazione. iOS 6
Tom Redman

2
qualche suggerimento su come modificare la durata però? CATransaction setAnimationDuration: non sembra fare la differenza.
Jeff Grimes

5
Funziona bene anche per me in iOS 5.1.1, 6.1, 7.0; Ma, se hai bisogno di ottenere un nuovo tableView.contentSize dopo l'animazione (come nel mio caso), devi usare [self performSelectorOnMainThread: withObject: waitUntilDone:]; in setCompletionBlock per chiamare il delegato nel ciclo di esecuzione successivo. se chiami il tuo delegato direttamente, senza performSelectorOnMainThread, ottieni il vecchio valore per tableView.contentSize.
slamor

38

Espandendo la bella risposta di karwag , si noti che su iOS 7, che circonda la transazione CAT con un'animazione UIView, offre il controllo della durata dell'animazione della tabella.

[UIView beginAnimations:@"myAnimationId" context:nil];

[UIView setAnimationDuration:10.0]; // Set duration here

[CATransaction begin];
[CATransaction setCompletionBlock:^{
    NSLog(@"Complete!");
}];

[myTable beginUpdates];
// my table changes
[myTable endUpdates];

[CATransaction commit];
[UIView commitAnimations];

La durata dell'animazione UIView non ha effetto su iOS 6. Forse le animazioni delle tabelle di iOS 7 sono implementate in modo diverso, a livello di UIView.


La durata dell'animazione sembra essere ignorata.
Dustin

26

È un trucchetto utile! Ho scritto un'estensione UITableView per evitare di scrivere cose CATransaction tutto il tempo.

import UIKit

extension UITableView {

    /// Perform a series of method calls that insert, delete, or select rows and sections of the table view.
    /// This is equivalent to a beginUpdates() / endUpdates() sequence, 
    /// with a completion closure when the animation is finished.
    /// Parameter update: the update operation to perform on the tableView.
    /// Parameter completion: the completion closure to be executed when the animation is completed.

    func performUpdate(_ update: ()->Void, completion: (()->Void)?) {

        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)

        // Table View update on row / section
        beginUpdates()
        update()
        endUpdates()

        CATransaction.commit()
    }

}

Questo è usato in questo modo:

// Insert in the tableView the section we just added in sections
self.tableView.performUpdate({
            self.tableView.insertSections([newSectionIndex], with: UITableViewRowAnimation.top)

        }, completion: {
            // Scroll to next section
            let nextSectionIndexPath = IndexPath(row: 0, section: newSectionIndex)
            self.tableView.scrollToRow(at: nextSectionIndexPath, at: .top, animated: true)
        })

Risposta fantastica! questo è uno dei motivi per cui amo Swift
Gianni Carlo

@GianniCarlo puoi farlo anche in ObjC
CyberMew

@CyberMew sì, ma creare una Categoria è sempre stato un tale dolore, soprattutto a causa dei nomi lunghi dei file extra
Gianni Carlo

è disponibile solo in ios 11, come si usa in ios 10?
kemdo

@kemdo Perché dici che è disponibile solo in iOS 11? Tutto qui è iOS 2+ tranne setCompletionBlockche è iOS 4+
Frédéric Adda

25

Abbreviando la bella risposta di Brent , per almeno iOS 7 puoi racchiudere tutto in modo conciso in una chiamata [UIView animateWithDuration: delay: options: animations: completamento:]:

[UIView animateWithDuration:10 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
  [self.tableView beginUpdates];
  [self.tableView endUpdates];
} completion:^(BOOL finished) {
  // completion code
}];

tuttavia, non riesco a sovrascrivere la curva di animazione predefinita da qualcosa di diverso da EaseInOut.


2
Quando si esegue una riga inserisce in questo modo, o alla maniera di @ Brent, sebbene la durata sia rispettata, la UITableViewRowAnimation non sembra essere rispettata e sembra sempre animarsi dall'alto verso il basso, anche quando specifico, ad esempio UITableViewRowAnimationLeft. Test su iOS 8.4: qualcuno ha una soluzione?
Danny

23

Ecco una versione rapida della risposta di karwag

    CATransaction.begin()
    tableView.beginUpdates()
    CATransaction.setCompletionBlock { () -> Void in
        // your code here
    }
    tableView.insertRowsAtIndexPaths(indexArray, withRowAnimation: .Top)
    tableView.endUpdates()
    CATransaction.commit()

6

Per me ne avevo bisogno per una collectionView. Ho creato una semplice estensione per risolvere questo problema:

extension UICollectionView {

    func reloadSections(sections: NSIndexSet, completion: () -> Void){
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)

        self.reloadSections(sections)

        CATransaction.commit()
    }

}

1

Poiché il performBatchmetodo tableView è disponibile solo a partire da iOS 11 , è possibile utilizzare la seguente estensione:

extension UITableView {
func performUpdates(_ updates: @escaping () -> Void, completion: @escaping (Bool) -> Void) {
        if #available(iOS 11.0, *) {
            self.performBatchUpdates({
                updates()
            }, completion: completion)
        } else {
            CATransaction.begin()
            beginUpdates()
            CATransaction.setCompletionBlock {
                completion(true)
            }
            updates()
            endUpdates()
            CATransaction.commit()
        }
    }
}

-8

Potresti provare a racchiudere insertRowsAtIndexPath in un file

- (void)beginUpdates
- (void)endUpdates

transazione, quindi eseguire il flash in seguito.


Vedi la risposta di karwag sopra. Devi risolvere il problema di ciò che conta come "dopo".
JLundell
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.