如何检测动画已经结束 UITableView 开始更新/结束更新?

我使用 beginUpdates/endUpdates中包装的 insertRowsAtIndexPaths/deleteRowsAtIndexPaths插入/删除表单元格。在调整 rowHeight 时,我也使用 beginUpdates/endUpdates。默认情况下,所有这些操作都是动画的。

当使用 beginUpdates/endUpdates时,我如何检测动画已经结束?

34094 次浏览

你可以这样使用 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];
}

但是,当已经在表中的单元格从屏幕移动到屏幕上时,也会调用这个函数,因此它可能并不完全是您想要的。我只是看了所有的 UITableViewUIScrollView委托方法,并没有出现任何处理后,单元格插入动画。


为什么不在 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];
}
}

还没有找到一个好的解决方案(除了子类化 UITableView)。我决定暂时使用 performSelector:withObject:afterDelay:。不是很理想,但能完成任务。

UPDATE: It looks like I can use scrollViewDidEndScrollingAnimation: for this purpose (this is specific to my implementation, see comment).

一种可能的解决方案是从 UITableView 继承,在该 UITableView 上调用 endUpdates并覆盖其 setContentSizeMethod,因为 UITableView 调整其内容大小以匹配添加或删除的行。这种方法也适用于 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;
}
}

这个怎么样?

[CATransaction begin];


[CATransaction setCompletionBlock:^{
// animation has finished
}];


[tableView beginUpdates];
// do some work
[tableView endUpdates];


[CATransaction commit];

这是因为 tableView 动画在内部使用 CALayer动画。也就是说,他们将动画添加到任何打开的 CATransaction。如果不存在打开的 CATransaction(正常情况下) ,则隐式开始一个 CATransaction,它在当前运行循环的末尾结束。但是如果你自己开始一个,就像这里做的,然后它会使用那个。

You can enclose your operation(s) in UIView animation block like so:

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

学分到 https://stackoverflow.com/a/12905114/634940

快速版


CATransaction.begin()


CATransaction.setCompletionBlock({
do.something()
})


tableView.beginUpdates()
tableView.endUpdates()


CATransaction.commit()

如果你的目标是 iOS11及以上版本,你应该改用 UITableView.performBatchUpdates(_:completion:):

tableView.performBatchUpdates({
// delete some cells
// insert some cells
}, completion: { finished in
// animation complete
})