UITableView行アニメーションの継続時間と完了のコールバック


98

UITableView行アニメーションの期間を指定する方法、またはアニメーションが完了したときにコールバックを取得する方法はありますか?

アニメーションが完了したら、スクロールインジケーターを点滅させます。その前にフラッシュを行っても何も起こりません。これまでのところ、私が持っている回避策は0.5秒遅らせることです(これはデフォルトのアニメーション期間のようです)、すなわち:

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

私は自分自身を試していないが、多分これはそれを行うことができ、いくつかのインデックスパスの扱いと:- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
カレ

回答:


3

現在、これを実行したい場合、iOS 11から始まる新しい機能があります。

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

更新クロージャーでは、beginUpdates()/ endUpdatesセクションと同じコードを配置します。そして、すべてのアニメーションの後に完了が実行されます。


これは素晴らしい。この追加に気づかなかった。
Daniel Dickison

207

ちょうどこれに遭遇しました。方法は次のとおりです。

Objective-C

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

迅速

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

2
繰り返しますが、ここで問題なく動作します。iOS6とすべて。これは、デフォルトのアニメーションのプロパティをオーバーライドするための、SDKがサポートする適切なメカニズムです。おそらく、CATransaction内に長時間実行される追加のアニメーションがありますか?入れ子になりますね。
カーワグ

1
iOS6で私に最適です。それをありがとう!
Aron

5
setAnimationDuration挿入/削除期間に影響を与えていないようです。iOS 6
トムレッドマン

2
期間を変更する方法についての提案はありますか?CATransaction setAnimationDuration:違いはないようです。
Jeff Grimes 2013年

5
私にとってもiOS 5.1.1、6.1、7.0では問題なく動作します。ただし、アニメーション後に新しいtableView.contentSizeを取得する必要がある場合(私の場合と同様)、[self performSelectorOnMainThread:withObject:waitUntilDone:]を使用する必要があります。次のrunloopでデリゲートを呼び出すために、setCompletionBlock内。performSelectorOnMainThreadなしでデリゲートを直接呼び出すと、tableView.contentSizeの古い値が取得されます。
2013

38

karwagの細かい答えを拡張すると、iOS 7では、UIViewアニメーションでCATransactionを囲むことで、テーブルアニメーションの継続時間を制御できることに注意してください。

[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アニメーションの継続時間はiOS 6には影響しません。おそらくiOS 7のテーブルアニメーションは、UIViewレベルで異なる方法で実装されています。


アニメーションの継続時間は無視されているようです。
ダスティン

26

これは便利なトリックの1つです。CATransactionに関するものを常に書くことを避けるために、UITableView拡張機能を書きました。

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

}

これは次のように使用されます。

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

素晴らしい答えです!これがSwiftが大好きな理由の1つです
ジャンニカルロ

@GianniCarloこれはObjCでも行うことができます
Cyber​​Mew 2018年

@Cyber​​Mewはい、ただし、特に追加ファイルの長い名前が原因で、カテゴリの作成は常に大変な作業でした
Gianni Carlo

iOS 11でのみ利用できます。iOS10での使用方法は?
kemdo 2018

@kemdoなぜiOS 11でしか利用できないと言うのですか?すべてはここ以外のiOS 2+であるsetCompletionBlock4+いるのiOSがある
フレデリック・ダッダ

25

ブレントの細かい答えを短くします。少なくともiOS 7では、これをすべて[UIView animateWithDuration:delay:options:animations:completion:]呼び出しで簡潔にラップできます。

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

ただし、EaseInOut以外のデフォルトのアニメーションカーブをオーバーライドすることはできません。


2
この方法または@Brentの方法で行を挿入すると、期間は尊重されますが、UITableViewRowAnimationLeftなどを指定しても、UITableViewRowAnimationは尊重されないようで、常にトップダウンでアニメーション表示されます。iOS 8.4でのテスト-誰かが解決策を持っていますか?
ダニー

23

これがカーワグの回答のスウィフトバージョンです

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

6

私にとっては、collectionViewにこれが必要でした。これを解決するために簡単な拡張を行いました:

extension UICollectionView {

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

        self.reloadSections(sections)

        CATransaction.commit()
    }

}

1

tableViewのperformBatchメソッドはiOS 11以降でのみ使用できるため、次の拡張機能を使用できます。

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

insertRowsAtIndexPathを

- (void)beginUpdates
- (void)endUpdates

その後、フラッシュを実行します。


上記のkarwagの回答を参照してください。「あとで」と見なされる問題を解決する必要があります。
JLundell
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.