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.