insertRowsAtIndexPaths/deleteRowsAtIndexPaths
でラップされたbeginUpdates/endUpdates
を使用して、テーブルセルを挿入/削除しています。また、rowHeightを調整するときにbeginUpdates/endUpdates
を使用しています。これらの操作はすべてデフォルトでアニメーション化されます。
beginUpdates/endUpdates
を使用しているときにアニメーションが終了したことを検出するにはどうすればよいですか?
これはどうですか?
[CATransaction begin];
[CATransaction setCompletionBlock:^{
// animation has finished
}];
[tableView beginUpdates];
// do some work
[tableView endUpdates];
[CATransaction commit];
これは、tableViewアニメーションがCALayer
アニメーションを内部的に使用するために機能します。つまり、開いているCATransaction
にアニメーションを追加します。開いているCATransaction
が存在しない場合(通常の場合)、暗黙的に開始され、現在のランループの終わりで終了します。ただし、ここで行われているように、自分で開始する場合は、それを使用します。
迅速なバージョン
CATransaction.begin()
CATransaction.setCompletionBlock({
do.something()
})
tableView.beginUpdates()
tableView.endUpdates()
CATransaction.commit()
次のように、UIViewアニメーションブロックで操作を囲むことができます。
- (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);
}];
}
UITableViewは追加または削除された行に合わせてコンテンツサイズを調整するため、可能な解決策は、endUpdates
を呼び出したUITableViewを継承し、setContentSizeMethod
を上書きすることです。このアプローチはreloadData
でも機能するはずです。
endUpdates
が呼び出された後にのみ通知が送信されるようにするには、endUpdates
を上書きしてフラグを設定することもできます。
// 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;
}
}
IOS 11以降をターゲットにしている場合は、代わりにUITableView.performBatchUpdates(_:completion:)
を使用する必要があります。
tableView.performBatchUpdates({
// delete some cells
// insert some cells
}, completion: { finished in
// animation complete
})
まだ良い解決策が見つかりませんでした(UITableViewのサブクラス化が短い)。今のところperformSelector:withObject:afterDelay:
を使用することにしました。理想的ではありませんが、仕事を成し遂げます。
[〜#〜] update [〜#〜]:この目的でscrollViewDidEndScrollingAnimation:
を使用できるようです(これは私の実装に固有です、コメントを参照してください)。
次のようにtableView:willDisplayCell:forRowAtIndexPath:
を使用できます。
- (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];
}
ただし、これは、既にテーブルにあるセルが画面外から画面上に移動したときにも呼び出されるため、探しているものとは異なる場合があります。すべてのUITableView
およびUIScrollView
デリゲートメソッドを調べたところ、セルがアニメーションを挿入した直後に処理するものは何もありません。
アニメーションがendUpdates
の後に終了したときに呼び出すメソッドを呼び出さないのはなぜですか?
- (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];
}
}