web-dev-qa-db-de.com

Wie kann man feststellen, dass die Animation auf UITableView beginUpdates/endUpdates beendet ist?

Ich füge/lösche eine Tabellenzelle mit insertRowsAtIndexPaths/deleteRowsAtIndexPaths in beginUpdates/endUpdates. Ich benutze auch beginUpdates/endUpdates, wenn Sie rowHeight anpassen. Alle diese Vorgänge werden standardmäßig animiert.

Wie kann ich feststellen, dass die Animation mit beginUpdates/endUpdates beendet ist?

107
pixelfreak

Was ist damit?

[CATransaction begin];

[CATransaction setCompletionBlock:^{
    // animation has finished
}];

[tableView beginUpdates];
// do some work
[tableView endUpdates];

[CATransaction commit];

Dies funktioniert, weil die tableView-Animationen intern CALayer-Animationen verwenden. Das heißt, sie fügen die Animationen zu allen offenen CATransaction hinzu. Wenn keine CATransaction offen ist (der Normalfall), wird implizit begonnen, was am Ende des aktuellen Runloop endet. Aber wenn Sie selbst eins anfangen, so wie hier, dann wird es dieses verwenden. 

284

Schnelle Version


CATransaction.begin()

CATransaction.setCompletionBlock({
    do.something()
})

tableView.beginUpdates()
tableView.endUpdates()

CATransaction.commit()
27
Michael

Sie können Ihre Vorgänge wie folgt in den UIView-Animationsblock einschließen:

- (void)tableView:(UITableView *)tableView performOperation:(void(^)())operation completion:(void(^)(BOOL finished))completion
{
    [UIView animateWithDuration:0.0 animations:^{

        [tableView beginUpdates];
        if (operation)
            operation();
        [tableView endUpdates];

    } completion:^(BOOL finished) {

        if (completion)
            completion(finished);
    }];
}

Kredite an https://stackoverflow.com/a/12905114/634940 .

5
Zdenek

Eine mögliche Lösung könnte sein, von der UITableView zu erben, in der Sie endUpdates aufrufen, und deren setContentSizeMethod überschreiben, da UITableView seine Inhaltsgröße an die hinzugefügten oder entfernten Zeilen anpasst. Dieser Ansatz sollte auch für reloadData funktionieren.

Um sicherzustellen, dass eine Benachrichtigung erst nach Aufruf von endUpdates gesendet wird, könnte endUpdates auch überschrieben und dort ein Flag gesetzt werden.

// somewhere in header
@private BOOL endUpdatesWasCalled_;

-------------------

// in implementation file

- (void)endUpdates {
    [super endUpdates];
    endUpdatesWasCalled_ = YES;
}

- (void)setContentSize:(CGSize)contentSize {
    [super setContentSize:contentSize];

    if (endUpdatesWasCalled_) {
        [self notifyEndUpdatesFinished];
        endUpdatesWasCalled_ = NO;
    }
}
4
Antoni

Ich habe noch keine gute Lösung gefunden (kurz UITableView). Ich habe mich entschieden, performSelector:withObject:afterDelay: vorerst zu verwenden. Nicht ideal, aber erledigt die Arbeit.

UPDATE: Es sieht so aus, als könnte ich scrollViewDidEndScrollingAnimation: für diesen Zweck verwenden (dies ist spezifisch für meine Implementierung, siehe Kommentar).

0
pixelfreak

Sie können tableView:willDisplayCell:forRowAtIndexPath: wie folgt verwenden:

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"tableView willDisplay Cell");
    cell.backgroundColor = [UIColor colorWithWhite:((indexPath.row % 2) ? 0.25 : 0) alpha:0.70];
}

Dies wird jedoch auch aufgerufen, wenn eine Zelle, die sich bereits in der Tabelle befindet, vom Bildschirm auf den Bildschirm verschoben wird, sodass es möglicherweise nicht genau das ist, wonach Sie suchen. Ich habe gerade alle Delegate-Methoden UITableView und UIScrollView durchgesehen, und es scheint nichts zu behandeln zu sein, kurz nachdem eine Animation eingefügt wurde.


Warum rufen Sie nicht einfach die Methode auf, die aufgerufen werden soll, wenn die Animation nach endUpdates endet?

- (void)setDownloadedImage:(NSMutableDictionary *)d {
    NSIndexPath *indexPath = (NSIndexPath *)[d objectForKey:@"IndexPath"];
    [indexPathDelayed addObject:indexPath];
    if (!([table isDragging] || [table isDecelerating])) {
        [table beginUpdates];
        [table insertRowsAtIndexPaths:indexPathDelayed withRowAnimation:UITableViewRowAnimationFade];
        [table endUpdates];
        // --> Call Method Here <--
        loadingView.hidden = YES;
        [indexPathDelayed removeAllObjects];
    }
}
0
chown

Wenn Sie auf iOS 11 oder höher abzielen, sollten Sie stattdessen UITableView.performBatchUpdates(_:completion:) verwenden:

tableView.performBatchUpdates({
    // delete some cells
    // insert some cells
}, completion: { finished in
    // animation complete
})
0
Robert