UITableView satır animasyon süresi ve tamamlama geri araması


99

UITableView satır animasyonları için süreyi belirtmenin veya animasyon tamamlandığında bir geri arama almanın bir yolu var mı?

Yapmak istediğim şey, animasyon tamamlandıktan sonra kaydırma göstergelerinin yanıp sönmesi. Flaşı daha önce yapmak hiçbir şey yapmaz. Şimdiye kadar sahip olduğum geçici çözüm yarım saniye geciktirmek (bu varsayılan animasyon süresi gibi görünüyor), yani:

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

Kendimi denemedim, ama belki bu, bazı dizin yollarının işlenmesi ile bunu yapabilir:- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
Kalle

Yanıtlar:


3

Bugünlerde bunu yapmak istiyorsanız , iOS 11'den başlayan yeni bir işlev var :

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

Güncelleme kapanışlarında beginUpdates () / endUpdates bölümündeki ile aynı kodu yerleştirirsiniz. Ve tamamlanma, tüm animasyonlardan sonra gerçekleştirilir.


Bu harika. Bu ilaveyi fark etmemiştim.
Daniel Dickison

207

Şimdi bununla karşılaştım. İşte nasıl yapılacağı:

Amaç-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
Yine burada kusursuz çalışıyor. iOS6 ve tümü. Bu, varsayılan animasyonlarda özellikleri geçersiz kılmak için uygun bir SDK destekli mekanizmadır. Belki de CATransaction içinde ek, daha uzun süre çalışan animasyonlar var? İç içe geçmişler, biliyorsun.
karwag

1
İOS6'da benim için harika çalışıyor. Bunun için teşekkürler!
Aron

5
setAnimationDurationekleme / silme süresini etkilemiyor gibi görünüyor. iOS 6
Tom Redman

2
Yine de süreyi nasıl değiştireceğiniz konusunda herhangi bir öneriniz var mı? CATransaction setAnimationDuration: bir fark yaratmıyor gibi görünüyor.
Jeff Grimes

5
İOS 5.1.1, 6.1, 7.0'da benim için de iyi çalışıyor; Ancak, animasyondan sonra yeni bir tableView.contentSize almanız gerekiyorsa (benim durumumda olduğu gibi), [self performSelectorOnMainThread: withObject: waitUntilDone:]; temsilcinizi sonraki runloop'ta çağırmak için setCompletionBlock'ta. temsilcinizi performSelectorOnMainThread olmadan doğrudan çağırırsanız, tableView.contentSize için eski değeri alırsınız.
2013

38

Karwag'ın iyi cevabını genişleterek, iOS 7'de CATransaction'ı bir UIView Animation ile çevrelemek, tablo animasyon süresinin kontrolünü sağladığını unutmayın.

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

UIView animasyonunun süresinin iOS 6 üzerinde hiçbir etkisi yoktur. Belki de iOS 7 tablo animasyonları UIView düzeyinde farklı şekilde uygulanır.


Animasyon süresi göz ardı edilmiş görünüyor.
Dustin

26

Bu çok faydalı bir numara! Sürekli CATransaction şeyler yazmaktan kaçınmak için bir UITableView uzantısı yazdım.

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

}

Bu şu şekilde kullanılır:

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

Harika cevap! Swift'i
sevmemin

@GianniCarlo bunu ObjC'de de yapabilirsiniz
CyberMew

@CyberMew evet, ancak bir Kategori oluşturmak her zaman çok zor olmuştur, özellikle de fazladan dosyaların uzun adları nedeniyle
Gianni Carlo

sadece ios 11'de mevcuttur, ios 10'da nasıl kullanılır?
kemdo

@kemdo Neden sadece iOS 11'de mevcut olduğunu söylüyorsunuz? Buradaki her şey iOS 2+ dışında setCompletionBlockiOS 4+
Frédéric Adda

25

Brent'in iyi cevabını kısaltmak , en azından iOS 7 için, bunu bir [UIView animateWithDuration: delay: options: animations: complete:] çağrısına kısaca sarabilirsiniz:

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

yine de, varsayılan animasyon eğrisini EaseInOut dışındaki herhangi bir şeyden geçersiz kılamıyorum.


2
Bu şekilde bir satır eklerken veya @ Brent'in yöntemiyle, süreye uyulmasına rağmen, UITableViewRowAnimation'a saygı duyulmuyor ve örneğin UITableViewRowAnimationLeft gibi belirttiğimde bile her zaman yukarıdan aşağıya hareket ediyor gibi görünüyor. İOS 8.4 üzerinde test - Kimsenin bir çözümü var mı?
Danny

23

İşte karwag'ın cevabının bir Swift versiyonu

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

7

Benim için bir collectionView için buna ihtiyacım vardı. Bunu çözmek için basit bir uzantı yaptım:

extension UICollectionView {

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

        self.reloadSections(sections)

        CATransaction.commit()
    }

}

1

TableView performBatchyöntemi yalnızca iOS 11'den itibaren mevcut olduğundan , aşağıdaki uzantıyı kullanabilirsiniz:

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

0

Antoine'ın cevabı oldukça iyi - ancak UICollectionView için. İşte UITableView için:

extension UITableView {
    func reloadSections(_ sections: IndexSet, with rowAnimation: RowAnimation, completion: (() -> Void)?) {
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)
        
        self.reloadSections(sections, with: rowAnimation)
        
        CATransaction.commit()
    }
}

Böyle çağırıldı:

tableView.reloadSections(IndexSet(0), with: .none, completion: {
    // Do the end of animation thing        
})

-8

İnsertRowsAtIndexPath'i bir

- (void)beginUpdates
- (void)endUpdates

işlem, ardından flaşı yapın.


Yukarıdaki karwag'ın cevabına bakın. Neyin "sonradan" sayıldığı sorununu çözmeniz gerekiyor.
JLundell
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.