ios 如何检测动画已在 UITableView beginUpdates/endUpdates 上结束?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7623771/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to detect that animation has ended on UITableView beginUpdates/endUpdates?
提问by pixelfreak
I am inserting/deleting table cell using insertRowsAtIndexPaths/deleteRowsAtIndexPaths
wrapped in beginUpdates/endUpdates
. I am also using beginUpdates/endUpdates
when adjusting rowHeight. All these operations are animated by default.
我正在使用insertRowsAtIndexPaths/deleteRowsAtIndexPaths
包裹在beginUpdates/endUpdates
. 我也在beginUpdates/endUpdates
调整 rowHeight时使用。默认情况下,所有这些操作都是动画的。
How can I detect that animation has ended when using beginUpdates/endUpdates
?
使用时如何检测动画已结束beginUpdates/endUpdates
?
回答by Rudolf Adamkovi?
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.
这是有效的,因为 tableViewCALayer
动画在内部使用动画。也就是说,他们将动画添加到任何打开的CATransaction
. 如果不CATransaction
存在open (正常情况),则隐式开始一个,在当前 runloop 结束时结束。但是如果你自己开始一个,就像这里完成的那样,那么它将使用那个。
回答by Michael
Swift Version
迅捷版
CATransaction.begin()
CATransaction.setCompletionBlock({
do.something()
})
tableView.beginUpdates()
tableView.endUpdates()
CATransaction.commit()
回答by Robert
If you're targeting iOS 11 and above, you should use UITableView.performBatchUpdates(_:completion:)
instead:
如果您的目标是 iOS 11 及更高版本,则应UITableView.performBatchUpdates(_:completion:)
改用:
tableView.performBatchUpdates({
// delete some cells
// insert some cells
}, completion: { finished in
// animation complete
})
回答by Zdenek
You can enclose your operation(s) in UIView animation block like so:
您可以将您的操作包含在 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);
}];
}
Credits to https://stackoverflow.com/a/12905114/634940.
回答by Antoni
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
.
一个可能的解决方案可能是从您调用的 UITableView 继承endUpdates
并覆盖其setContentSizeMethod
,因为 UITableView 会调整其内容大小以匹配添加或删除的行。这种方法也应该适用于reloadData
.
To ensure that a notification is sent only after endUpdates
is called, one could also overwrite endUpdates
and set a flag there.
为了确保只有在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;
}
}
回答by pixelfreak
Haven't found a good solution yet (short of subclassing UITableView). I've decided to use performSelector:withObject:afterDelay:
for now. Not ideal, but gets the job done.
还没有找到一个好的解决方案(缺少子类化 UITableView)。我决定暂时使用performSelector:withObject:afterDelay:
。不理想,但可以完成工作。
UPDATE: It looks like I can use scrollViewDidEndScrollingAnimation:
for this purpose (this is specific to my implementation, see comment).
更新:看起来我可以scrollViewDidEndScrollingAnimation:
用于此目的(这是特定于我的实现,请参阅评论)。
回答by chown
You can use tableView:willDisplayCell:forRowAtIndexPath:
like:
你可以使用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];
}
But this will also get called when a cell that is already in the table moves from off the screen to on the screen so it may not be exactly what you are looking for. I just looked through all the UITableView
and UIScrollView
delegate methods and there doesnt appear to be anything to handle just after a cell is inserted animation.
但是,当表格中已经存在的单元格从屏幕外移动到屏幕上时,这也会被调用,因此它可能不是您正在寻找的内容。我只是查看了所有UITableView
和UIScrollView
委托方法,在插入单元格动画后似乎没有任何处理。
Why not just call the method you want to be called when the animation ends after the endUpdates
?
为什么不直接调用你想在动画结束时调用的方法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];
}
}