我使用 beginUpdates/endUpdates中包装的 insertRowsAtIndexPaths/deleteRowsAtIndexPaths插入/删除表单元格。在调整 rowHeight 时,我也使用 beginUpdates/endUpdates。默认情况下,所有这些操作都是动画的。
beginUpdates/endUpdates
insertRowsAtIndexPaths/deleteRowsAtIndexPaths
当使用 beginUpdates/endUpdates时,我如何检测动画已经结束?
你可以这样使用 tableView:willDisplayCell:forRowAtIndexPath::
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委托方法,并没有出现任何处理后,单元格插入动画。
UITableView
UIScrollView
为什么不在 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]; } }
还没有找到一个好的解决方案(除了子类化 UITableView)。我决定暂时使用 performSelector:withObject:afterDelay:。不是很理想,但能完成任务。
performSelector:withObject:afterDelay:
UPDATE: It looks like I can use scrollViewDidEndScrollingAnimation: for this purpose (this is specific to my implementation, see comment).
scrollViewDidEndScrollingAnimation:
一种可能的解决方案是从 UITableView 继承,在该 UITableView 上调用 endUpdates并覆盖其 setContentSizeMethod,因为 UITableView 调整其内容大小以匹配添加或删除的行。这种方法也适用于 reloadData。
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; } }
这个怎么样?
[CATransaction begin]; [CATransaction setCompletionBlock:^{ // animation has finished }]; [tableView beginUpdates]; // do some work [tableView endUpdates]; [CATransaction commit];
这是因为 tableView 动画在内部使用 CALayer动画。也就是说,他们将动画添加到任何打开的 CATransaction。如果不存在打开的 CATransaction(正常情况下) ,则隐式开始一个 CATransaction,它在当前运行循环的末尾结束。但是如果你自己开始一个,就像这里做的,然后它会使用那个。
CALayer
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:):
UITableView.performBatchUpdates(_:completion:)
tableView.performBatchUpdates({ // delete some cells // insert some cells }, completion: { finished in // animation complete })