UITableView-Zeilenanimationsdauer und Abschlussrückruf

98

Gibt es eine Möglichkeit, entweder die Dauer für UITableView-Zeilenanimationen anzugeben oder einen Rückruf zu erhalten, wenn die Animation abgeschlossen ist?

Ich möchte die Bildlaufanzeigen nach Abschluss der Animation blinken lassen. Vorher den Blitz zu machen, macht nichts. Bisher besteht die Problemumgehung darin, eine halbe Sekunde zu verzögern (dies scheint die Standardanimationsdauer zu sein), dh:

[self.tableView insertRowsAtIndexPaths:newRows
                      withRowAnimation:UITableViewRowAnimationFade];
[self.tableView performSelector:@selector(flashScrollIndicators)
                     withObject:nil
                     afterDelay:0.5];
Daniel Dickison
quelle
Ich habe es selbst nicht versucht, aber vielleicht könnte dies mit etwas Indexpfad-Handling geschehen:- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
Kalle

Antworten:

3

Wenn Sie dies tun möchten, gibt es heutzutage eine neue Funktion ab iOS 11 :

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

In Aktualisierungsabschlüssen platzieren Sie denselben Code wie im Abschnitt beginUpdates () / endUpdates. Und die Fertigstellung wird nach allen Animationen ausgeführt.

Michał Ziobro
quelle
Das ist toll. Ich hatte diesen Zusatz nicht bemerkt.
Daniel Dickison
207

Bin gerade darauf gestoßen. So geht's:

Ziel c

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

Schnell

CATransaction.begin()
tableView.beginUpdates()
CATransaction.setCompletionBlock {
    // Code to be executed upon completion
}
tableView.insertRowsAtIndexPaths(indexArray, withRowAnimation: .Top)
tableView.endUpdates()
CATransaction.commit()
Karwag
quelle
2
Auch hier funktioniert einwandfrei. iOS6 und alle. Dies ist ein geeigneter SDK-unterstützter Mechanismus zum Überschreiben von Eigenschaften in Standardanimationen. Vielleicht haben Sie zusätzliche, länger laufende Animationen in Ihrer CATransaction? Sie werden verschachtelt, wissen Sie.
Karwag
1
Funktioniert hervorragend für mich in iOS6. Dank dafür!
Aron
5
setAnimationDurationscheint die Einfüge- / Löschdauer nicht zu beeinflussen. iOS 6
Tom Redman
2
Irgendwelche Vorschläge, wie man die Dauer ändert? CATransaction setAnimationDuration: scheint keinen Unterschied zu machen.
Jeff Grimes
5
Funktioniert auch für mich in iOS 5.1.1, 6.1, 7.0; Wenn Sie jedoch nach der Animation eine neue tableView.contentSize benötigen (wie in meinem Fall), müssen Sie [self performSelectorOnMainThread: withObject: waitUntilDone:] verwenden. in setCompletionBlock, um Ihren Delegaten im nächsten Runloop aufzurufen. Wenn Sie Ihren Delegaten direkt ohne performSelectorOnMainThread aufrufen, erhalten Sie den alten Wert für tableView.contentSize.
Slamor
38

Aufbauend auf karwag der feinen Antwort , beachten Sie, dass auf iOS 7, rund um das CATransaction mit einer UIView - Animation bietet die Kontrolle über die Tisch Animationsdauer.

[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];

Die Dauer der UIView-Animation hat keinen Einfluss auf iOS 6. Möglicherweise werden iOS 7-Tabellenanimationen auf UIView-Ebene anders implementiert.

Brent
quelle
Die Animationsdauer scheint ignoriert zu werden.
Dustin
26

Das ist ein verdammt nützlicher Trick! Ich habe eine UITableView-Erweiterung geschrieben, um zu vermeiden, dass ständig CATransaction-Inhalte geschrieben werden.

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()
    }

}

Dies wird wie folgt verwendet:

// 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)
        })
Frédéric Adda
quelle
Super Antwort! Dies ist einer der Gründe, warum ich Swift liebe
Gianni Carlo
@ GianniCarlo Sie können dies auch in ObjC tun
CyberMew
@CyberMew ja, aber das Erstellen einer Kategorie war schon immer ein Problem, insbesondere aufgrund der langen Namen der zusätzlichen Dateien
Gianni Carlo
Es ist nur in iOS 11 verfügbar. Wie wird es in iOS 10 verwendet?
Kemdo
@kemdo Warum ist es Ihrer Meinung nach nur in iOS 11 verfügbar? Alles hier ist iOS 2+, außer setCompletionBlockiOS 4+
Frédéric Adda
25

Wenn Sie Brents feine Antwort verkürzen, können Sie dies für mindestens iOS 7 kurz und bündig in einen Aufruf von [UIView animateWithDuration: delay: options: animations: finish:] einbinden:

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

Ich kann die Standardanimationskurve jedoch nicht von etwas anderem als EaseInOut überschreiben.

visnu
quelle
2
Wenn Sie eine Zeile auf diese Weise oder auf die Art von @ Brent einfügen, scheint die UITableViewRowAnimation, obwohl die Dauer eingehalten wird, nicht berücksichtigt zu werden und scheint immer von oben nach unten zu animieren, selbst wenn ich beispielsweise UITableViewRowAnimationLeft spezifiziere. Testen unter iOS 8.4 - hat jemand eine Lösung?
Danny
23

Hier ist eine Swift-Version von Karwags Antwort

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

Für mich brauchte ich das für eine collectionView. Ich habe eine einfache Erweiterung vorgenommen, um dies zu lösen:

extension UICollectionView {

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

        self.reloadSections(sections)

        CATransaction.commit()
    }

}
Antoine
quelle
1

Da die performBatchMethode von tableView nur ab iOS 11 verfügbar ist , können Sie die folgende Erweiterung verwenden:

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()
        }
    }
}
Stanislau Baranouski
quelle
-8

Sie könnten versuchen, den insertRowsAtIndexPath in a zu verpacken

- (void)beginUpdates
- (void)endUpdates

Transaktion, dann machen Sie den Flash danach.

Jordanien
quelle
Siehe Karwags Antwort oben. Sie müssen das Problem lösen, was als "danach" gilt.
JLundell