What about this?
[CATransaction begin];
[CATransaction setCompletionBlock:^{
// animation has finished
}];
[tableView beginUpdates];
// do some work
[tableView endUpdates];
[CATransaction commit];
This works because the tableView animations use CALayer
animations internally. That is, they add the animations to any open CATransaction
. If no open CATransaction
exists (the normal case), then one is implicitly began, which is ended at the end of the current runloop. But if you begin one yourself, like is done here, then it will use that one.
Swift Version
CATransaction.begin()
CATransaction.setCompletionBlock({
do.something()
})
tableView.beginUpdates()
tableView.endUpdates()
CATransaction.commit()
If you're targeting iOS 11 and above, you should use UITableView.performBatchUpdates(_:completion:)
instead:
tableView.performBatchUpdates({
// delete some cells
// insert some cells
}, completion: { finished in
// animation complete
})
A possible solution could be to inherit from the UITableView on which you call endUpdates
and overwrite its setContentSizeMethod
, since UITableView adjusts its content size to match the added or removed rows. This approach should also work for reloadData
.
To ensure that a notification is sent only after endUpdates
is called, one could also overwrite endUpdates
and set a flag there.
// 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;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With