Czas trwania animacji wiersza UITableView i wywołanie zwrotne zakończenia


98

Czy istnieje sposób określenia czasu trwania animacji wiersza UITableView lub uzyskania wywołania zwrotnego po zakończeniu animacji?

To, co chciałbym zrobić, to migać wskaźnikami przewijania po zakończeniu animacji. Wykonanie flashowania przedtem nic nie robi. Jak dotąd obejściem, które mam, jest opóźnienie o pół sekundy (wydaje się, że jest to domyślny czas trwania animacji), tj .:

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

Sam nie próbowałem, ale może to się uda, z pewną obsługą ścieżki indeksu:- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
Kalle

Odpowiedzi:


3

Obecnie, jeśli chcesz to zrobić, pojawiła się nowa funkcja począwszy od iOS 11 :

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

W zamknięciach aktualizacji umieszczasz ten sam kod, co w sekcji beginUpdates () / endUpdates. Zakończenie jest wykonywane po wszystkich animacjach.


To jest świetne. Nie zauważyłem tego dodatku.
Daniel Dickison,

207

Właśnie to spotkałem. Oto jak to zrobić:

Cel C

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

Szybki

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

2
Ponownie działa tutaj bez zarzutu. iOS6 i wszystkie. Jest to poprawny mechanizm obsługiwany przez SDK do zastępowania właściwości w domyślnych animacjach. Być może masz dodatkowe, dłużej działające animacje wewnątrz swojej transakcji CAT? Wiesz, że się zagnieżdżają.
karwag

1
U mnie działa świetnie w iOS6. Dziękuję za to!
Aron,

5
setAnimationDurationnie wydaje się mieć wpływu na czas trwania wstawiania / usuwania. iOS 6
Tom Redman,

2
jakieś sugestie, jak zmienić czas trwania? CATransaction setAnimationDuration: wydaje się, że nie robi różnicy.
Jeff Grimes,

5
U mnie też działa dobrze w iOS 5.1.1, 6.1, 7.0; Ale jeśli chcesz uzyskać nowy tableView.contentSize po animacji (tak jak to było w moim przypadku), musisz użyć [self performSelectorOnMainThread: withObject: waitUntilDone:]; w setCompletionBlock w celu wywołania delegata w następnym runloop. jeśli wywołasz delegata bezpośrednio, bez performSelectorOnMainThread, otrzymasz starą wartość dla tableView.contentSize.
slamour

38

Rozwijając dobrą odpowiedź Karwaga , zauważ, że na iOS 7 otoczenie transakcji CAT animacją UIView zapewnia kontrolę nad czasem trwania animacji tabeli.

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

Czas trwania animacji UIView nie ma wpływu na iOS 6. Być może animacje tabel w iOS 7 są implementowane inaczej, na poziomie UIView.


Wydaje się, że czas trwania animacji jest ignorowany.
Dustin

26

To cholernie przydatna sztuczka! Napisałem rozszerzenie UITableView, aby uniknąć ciągłego pisania elementów CATransaction.

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

}

Jest to używane w następujący sposób:

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

Świetna odpowiedź! to jeden z powodów, dla których uwielbiam Swift
Gianni Carlo,

@GianniCarlo możesz to zrobić również w ObjC
CyberMew

@CyberMew tak, ale tworzenie kategorii zawsze było uciążliwe, szczególnie ze względu na długie nazwy dodatkowych plików
Gianni Carlo

jest dostępny tylko w ios 11, jak go używać w ios 10?
kemdo

@kemdo Dlaczego mówisz, że jest dostępny tylko w iOS 11? Wszystko tutaj to iOS 2+, z wyjątkiem setCompletionBlockiOS 4+
Frédéric Adda

25

Skracając dobrą odpowiedź Brenta , przynajmniej dla iOS 7 możesz zawinąć to wszystko zwięźle w [UIView animateWithDuration: delay: options: animations: complete:] call:

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

jednak wydaje mi się, że nie mogę zastąpić domyślnej krzywej animacji z niczego innego niż EaseInOut.


2
Podczas wstawiania wiersza w ten sposób lub w sposób @ Brent, chociaż czas trwania jest przestrzegany, UITableViewRowAnimation nie wydaje się być przestrzegany i zawsze wydaje się być animowany z góry na dół, nawet jeśli określę, na przykład UITableViewRowAnimationLeft. Testowanie na iOS 8.4 - ktoś ma rozwiązanie?
Danny

23

Oto szybka wersja odpowiedzi karwaga

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

6

Dla mnie potrzebowałem tego dla collectionView. Zrobiłem proste rozszerzenie, aby rozwiązać ten problem:

extension UICollectionView {

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

        self.reloadSections(sections)

        CATransaction.commit()
    }

}

1

Ponieważ performBatchmetoda tableView jest dostępna tylko od iOS 11 , możesz użyć następującego rozszerzenia:

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

Możesz spróbować opakować insertRowsAtIndexPath w plik

- (void)beginUpdates
- (void)endUpdates

transakcja, a następnie wykonaj flashowanie.


Zobacz odpowiedź Karwaga powyżej. Musisz rozwiązać problem tego, co liczy się jako „później”.
JLundell
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.