UITableView 行动画持续时间和完成回调
Posted
技术标签:
【中文标题】UITableView 行动画持续时间和完成回调【英文标题】:UITableView row animation duration and completion callback 【发布时间】:2011-04-19 10:47:05 【问题描述】:有没有办法指定 UITableView 行动画的持续时间,或者在动画完成时获取回调?
我想做的是在动画完成后闪烁滚动指示器。在那之前做闪光灯没有任何作用。到目前为止,我的解决方法是延迟半秒(这似乎是默认的动画持续时间),即:
[self.tableView insertRowsAtIndexPaths:newRows
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView performSelector:@selector(flashScrollIndicators)
withObject:nil
afterDelay:0.5];
【问题讨论】:
我自己没试过,但也许可以通过一些索引路径处理来做到这一点:- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
【参考方案1】:
您可以尝试将 insertRowsAtIndexPath 包装在
中- (void)beginUpdates
- (void)endUpdates
事务,然后做flash。
【讨论】:
见上面karwag的回答。你需要解决什么算“后来”的问题。【参考方案2】:刚刚遇到这个。操作方法如下:
Objective-C
[CATransaction begin];
[tableView beginUpdates];
[CATransaction setCompletionBlock: ^
// Code to be executed upon completion
];
[tableView insertRowsAtIndexPaths: indexPaths
withRowAnimation: UITableViewRowAnimationAutomatic];
[tableView endUpdates];
[CATransaction commit];
斯威夫特
CATransaction.begin()
tableView.beginUpdates()
CATransaction.setCompletionBlock
// Code to be executed upon completion
tableView.insertRowsAtIndexPaths(indexArray, withRowAnimation: .Top)
tableView.endUpdates()
CATransaction.commit()
【讨论】:
再次,在这里完美运行。 ios6 和所有。这是一种适当的 SDK 支持机制,用于覆盖默认动画中的属性。也许您的 CATransaction 中有额外的、运行时间更长的动画?你知道,它们是嵌套的。 在 iOS6 中非常适合我。谢谢!setAnimationDuration
似乎不会影响插入/删除持续时间。 iOS 6
关于如何更改持续时间的任何建议? CATransaction setAnimationDuration: 似乎没有什么区别。
在 iOS 5.1.1、6.1、7.0 中也适用于我;但是,如果您需要在动画后获得一个新的 tableView.contentSize(就像我的情况一样),您必须使用 [self performSelectorOnMainThread:withObject:waitUntilDone:];在 setCompletionBlock 中,以便在下一个运行循环中调用您的委托。如果您直接调用您的委托,而不使用 performSelectorOnMainThread,您将获得 tableView.contentSize 的旧值。【参考方案3】:
扩展 karwag's fine answer,注意在 iOS 7 上,使用 UIView 动画围绕 CATransaction 提供对表格动画持续时间的控制。
[UIView beginAnimations:@"myAnimationId" context:nil];
[UIView setAnimationDuration:10.0]; // Set duration here
[CATransaction begin];
[CATransaction setCompletionBlock:^
NSLog(@"Complete!");
];
[myTable beginUpdates];
// my table changes
[myTable endUpdates];
[CATransaction commit];
[UIView commitAnimations];
UIView 动画的持续时间对 iOS 6 没有影响。也许 iOS 7 表格动画的实现方式不同,在 UIView 级别。
【讨论】:
动画持续时间似乎被忽略了。【参考方案4】:缩短 Brent's fine answer,至少对于 iOS 7,您可以将这一切简洁地包装在 [UIView animateWithDuration:delay:options:animations:completion:] 调用中:
[UIView animateWithDuration:10 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^
[self.tableView beginUpdates];
[self.tableView endUpdates];
completion:^(BOOL finished)
// completion code
];
不过,除了 EaseInOut 之外,我似乎无法覆盖默认动画曲线。
【讨论】:
当以这种方式或@Brent 的方式进行行插入时,虽然持续时间得到尊重,但 UITableViewRowAnimation 似乎没有得到尊重,并且总是出现自上而下的动画,即使我指定了,例如UITableViewRowAnimationLeft。在 iOS 8.4 上进行测试 - 有人有解决方案吗?【参考方案5】:对我来说,我需要这个作为 collectionView。我做了一个简单的扩展来解决这个问题:
extension UICollectionView
func reloadSections(sections: NSIndexSet, completion: () -> Void)
CATransaction.begin()
CATransaction.setCompletionBlock(completion)
self.reloadSections(sections)
CATransaction.commit()
【讨论】:
【参考方案6】:这是karwag's answer 的 Swift 版本
CATransaction.begin()
tableView.beginUpdates()
CATransaction.setCompletionBlock () -> Void in
// your code here
tableView.insertRowsAtIndexPaths(indexArray, withRowAnimation: .Top)
tableView.endUpdates()
CATransaction.commit()
【讨论】:
【参考方案7】:这是一个非常有用的技巧! 我写了一个 UITableView 扩展来避免一直写 CATransaction 的东西。
import UIKit
extension UITableView
/// Perform a series of method calls that insert, delete, or select rows and sections of the table view.
/// This is equivalent to a beginUpdates() / endUpdates() sequence,
/// with a completion closure when the animation is finished.
/// Parameter update: the update operation to perform on the tableView.
/// Parameter completion: the completion closure to be executed when the animation is completed.
func performUpdate(_ update: ()->Void, completion: (()->Void)?)
CATransaction.begin()
CATransaction.setCompletionBlock(completion)
// Table View update on row / section
beginUpdates()
update()
endUpdates()
CATransaction.commit()
这样使用:
// Insert in the tableView the section we just added in sections
self.tableView.performUpdate(
self.tableView.insertSections([newSectionIndex], with: UITableViewRowAnimation.top)
, completion:
// Scroll to next section
let nextSectionIndexPath = IndexPath(row: 0, section: newSectionIndex)
self.tableView.scrollToRow(at: nextSectionIndexPath, at: .top, animated: true)
)
【讨论】:
很棒的答案!这是我喜欢 Swift 的原因之一 @GianniCarlo 你也可以在 ObjC 中做到这一点 @CyberMew 是的,但是创建类别一直很痛苦,特别是由于额外文件的名称很长 只有ios 11才有,ios 10怎么用? @kemdo 为什么说它只在 iOS 11 中可用?这里的一切都是 iOS 2+ 除了setCompletionBlock
这是 iOS 4+【参考方案8】:
现在如果你想这样做,有新功能starting from iOS 11:
- (void)performBatchUpdates:(void (^)(void))updates
completion:(void (^)(BOOL finished))completion;
在更新闭包中放置与 beginUpdates()/endUpdates 部分相同的代码。并且完成在所有动画之后执行。
【讨论】:
这很棒。我没有注意到这个添加。【参考方案9】:由于 tableView 的 performBatch
方法仅从 iOS 11 开始可用,您可以使用以下扩展:
extension UITableView
func performUpdates(_ updates: @escaping () -> Void, completion: @escaping (Bool) -> Void)
if #available(iOS 11.0, *)
self.performBatchUpdates(
updates()
, completion: completion)
else
CATransaction.begin()
beginUpdates()
CATransaction.setCompletionBlock
completion(true)
updates()
endUpdates()
CATransaction.commit()
【讨论】:
【参考方案10】:Antoine's answer 非常好——但适用于 UICollectionView。这是 UITableView:
extension UITableView
func reloadSections(_ sections: IndexSet, with rowAnimation: RowAnimation, completion: (() -> Void)?)
CATransaction.begin()
CATransaction.setCompletionBlock(completion)
self.reloadSections(sections, with: rowAnimation)
CATransaction.commit()
这样称呼:
tableView.reloadSections(IndexSet(0), with: .none, completion:
// Do the end of animation thing
)
【讨论】:
【参考方案11】:如果有人在 tableView 忽略 UIView.animate 中的动画参数并使用“从上到下”默认动画重新加载行时遇到问题,我找到了一个奇怪的解决方案:
你需要:
-
静音tableView动画
改用transitionAnimation
例子:
let indicesToUpdate = [IndexPath(row: 1, section: 0)]
UIView.transition(with: self.tableView,
duration: 0.5,
options: [.transitionCrossDissolve,
.allowUserInteraction,
.beginFromCurrentState],
animations:
UIView.performWithoutAnimation
self.tableView.reloadRows(at: indicesToUpdate,
with: .none)
)
PS:UIView.transition(..) 也有可选的补全:)
【讨论】:
以上是关于UITableView 行动画持续时间和完成回调的主要内容,如果未能解决你的问题,请参考以下文章
回调:动画完成:在 .promise().done() 之后调用
有没有办法控制 UITableView scrollToRowAtIndexPath 上的动画?
UITableView beginUpdates/endUpdates 回调