Durasi animasi baris UITableView dan callback penyelesaian

98

Apakah ada cara untuk menentukan durasi animasi baris UITableView, atau untuk mendapatkan callback saat animasi selesai?

Yang ingin saya lakukan adalah mem-flash indikator gulir setelah animasi selesai. Melakukan flash sebelum itu tidak melakukan apa-apa. Sejauh ini solusi yang saya miliki adalah menunda setengah detik (yang tampaknya merupakan durasi animasi default), yaitu:

[self.tableView insertRowsAtIndexPaths:newRows
                      withRowAnimation:UITableViewRowAnimationFade];
[self.tableView performSelector:@selector(flashScrollIndicators)
                     withObject:nil
                     afterDelay:0.5];
Daniel Dickison
sumber
Saya belum mencoba sendiri, tetapi mungkin ini bisa melakukannya, dengan beberapa penanganan jalur indeks:- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
Kalle

Jawaban:

3

Saat ini jika Anda ingin melakukan ini, ada fungsi baru mulai dari iOS 11 :

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

Dalam penutupan pembaruan, Anda menempatkan kode yang sama seperti di bagian beginUpdates () / endUpdates. Dan penyelesaiannya dilakukan setelah semua animasi.

Michał Ziobro
sumber
Ini bagus. Saya tidak memperhatikan penambahan ini.
Daniel Dickison
207

Baru saja menemukan ini. Berikut cara melakukannya:

Objective-C

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

Cepat

CATransaction.begin()
tableView.beginUpdates()
CATransaction.setCompletionBlock {
    // Code to be executed upon completion
}
tableView.insertRowsAtIndexPaths(indexArray, withRowAnimation: .Top)
tableView.endUpdates()
CATransaction.commit()
karwag
sumber
2
Sekali lagi, bekerja dengan sempurna di sini. iOS6 dan semuanya. Ini adalah mekanisme yang didukung SDK yang tepat untuk mengganti properti dalam animasi default. Mungkin Anda memiliki animasi tambahan yang berjalan lebih lama di dalam CATransaction Anda? Mereka bersarang, Anda tahu.
karwag
1
Sangat cocok untuk saya di iOS6. Terima kasih untuk itu!
Aron
5
setAnimationDurationsepertinya tidak memengaruhi durasi penyisipan / penghapusan. iOS 6
Tom Redman
2
ada saran untuk bagaimana mengubah durasi? CATransaction setAnimationDuration: sepertinya tidak membuat perbedaan.
Jeff Grimes
5
Bekerja dengan baik untuk saya juga di iOS 5.1.1, 6.1, 7.0; Tetapi, jika Anda perlu mendapatkan tableView.contentSize baru setelah animasi (seperti dalam kasus saya), Anda harus menggunakan [self performSelectorOnMainThread: withObject: waitUntilDone:]; di setCompletionBlock untuk memanggil delegasi Anda di runloop berikutnya. jika Anda memanggil delegasi Anda secara langsung, tanpa performSelectorOnMainThread, Anda akan mendapatkan nilai lama untuk tableView.contentSize.
slamour
38

Memperluas jawaban karwag yang bagus , perhatikan bahwa pada iOS 7, seputar CATransaction dengan UIView Animation menawarkan kontrol durasi animasi tabel.

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

Durasi animasi UIView tidak berpengaruh pada iOS 6. Mungkin animasi tabel iOS 7 diimplementasikan secara berbeda, di level UIView.

Brent
sumber
Durasi animasi tampaknya diabaikan.
Dustin
26

Itu salah satu trik yang sangat berguna! Saya menulis ekstensi UITableView untuk menghindari menulis hal-hal CATransaction sepanjang waktu.

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

}

Ini digunakan seperti ini:

// 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
sumber
Jawaban yang luar biasa! ini adalah salah satu alasan saya menyukai Swift
Gianni Carlo
@GianniCarlo Anda dapat melakukan ini juga di ObjC
CyberMew
@CyberMew ya, tetapi membuat Kategori selalu menyebalkan, khususnya karena nama panjang dari file tambahan
Gianni Carlo
itu hanya tersedia di ios 11, bagaimana cara menggunakannya di ios 10?
kemdo
@kemdo Mengapa Anda mengatakan itu hanya tersedia di iOS 11? Semuanya di sini adalah iOS 2+ kecuali setCompletionBlockyang iOS 4+
Frédéric Adda
25

Mempersingkat jawaban bagus Brent , untuk setidaknya iOS 7 Anda dapat menggabungkan semua ini dengan singkat dalam panggilan [UIView animateWithDuration: delay: options: animations: complete:]:

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

meskipun, saya tidak bisa menimpa kurva animasi default dari apa pun selain EaseInOut.

Visnu
sumber
2
Saat melakukan penyisipan baris dengan cara ini, atau dengan cara @ Brent, meskipun durasinya dipatuhi, UITableViewRowAnimation tampaknya tidak dipatuhi dan selalu tampak beranimasi dari atas ke bawah, bahkan saat saya tentukan, misalnya UITableViewRowAnimationLeft. Menguji di iOS 8.4 - ada yang punya solusinya?
Danny
23

Inilah jawaban karwag versi Swift

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

Bagi saya, saya membutuhkan ini untuk collectionView. Saya telah membuat ekstensi sederhana untuk menyelesaikan ini:

extension UICollectionView {

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

        self.reloadSections(sections)

        CATransaction.commit()
    }

}
Antoine
sumber
1

Karena performBatchmetode tableView tersedia mulai dari iOS 11 saja, Anda dapat menggunakan ekstensi berikut:

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
sumber
-8

Anda dapat mencoba menggabungkan insertRowsAtIndexPath dalam file

- (void)beginUpdates
- (void)endUpdates

transaksi, lalu lakukan flash setelahnya.

Yordania
sumber
Lihat jawaban karwag di atas. Anda perlu memecahkan masalah yang dianggap sebagai "sesudahnya".
JLundell