调用reloadItemsAtIndexPaths之后,UICollectionView会设置动画项目(淡入动画)。
有办法避免这种动画吗?
iOS 6
Answers:
值得注意的是,如果您的目标是iOS 7及更高版本,则可以使用newUIView
方法performWithoutAnimation:
。我怀疑这实际上与这里的其他答案(暂时禁用UIView
动画/ Core Animation动作)的作用大致相同,但语法很好。
因此,对于这个问题尤其如此...
目标C:
[UIView performWithoutAnimation:^{
[self.collectionView reloadItemsAtIndexPaths:indexPaths];
}];
迅速:
UIView.performWithoutAnimation {
self.collectionView.reloadItemsAtIndexPaths(indexPaths)
}
当然,该原理可以应用于您要确保更改没有变化的任何情况。
您也可以尝试以下方法:
UICollectionView *collectionView;
...
[UIView setAnimationsEnabled:NO];
[collectionView performBatchUpdates:^{
[collectionView reloadItemsAtIndexPaths:indexPaths];
} completion:^(BOOL finished) {
[UIView setAnimationsEnabled:YES];
}];
我还发现,如果包装performBatchUpdates
在UIView动画块中,则将使用UIView动画而不是默认动画,因此可以将动画持续时间设置为0,如下所示:
[UIView animateWithDuration:0 animations:^{
[collectionView performBatchUpdates:^{
[collectionView reloadItemsAtIndexPaths:indexPaths];
} completion:nil];
}];
如果要在插入和删除过程中使用iOS 7弹性动画,这将特别酷!
performBatchUpdates
内部真是太好了animateWithDuration
!谢谢你的提示!
调用reloadItemsAtIndexPaths之后,UICollectionView会设置动画项目(淡入动画)。
有办法避免这种动画吗?
iOS 6
我假设您正在使用FlowLayout。由于您要摆脱淡入淡出的动画,请尝试以下操作:
import UIKit
class NoFadeFlowLayout: UICollectionViewFlowLayout {
override func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attrs = super.initialLayoutAttributesForAppearingItem(at: itemIndexPath)
attrs?.alpha = 1.0
return attrs
}
override func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
let attrs = super.finalLayoutAttributesForDisappearingItem(at: itemIndexPath)
attrs?.alpha = 1.0
return attrs
}
}
这是一个非常老的问题,因此您可能不再针对iOS 6。我亲自在tvOS 11上工作,并遇到了相同的问题,所以对于那些遇到相同问题的人来说,这就是这里。
我在UICollectionView上编写了一个类别来实现这一目的。技巧是在重新加载时禁用所有动画:
if (!animated) {
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
}
[self reloadItemsAtIndexPaths:indexPaths];
if (!animated) {
[CATransaction commit];
}
CATransaction.setDisableActions(true)
为此做一个简写。
extension UICollectionView {
func reloadWithoutAnimation(){
CATransaction.begin()
CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
self.reloadData()
CATransaction.commit()
}
}
这是Swift 3版本,performBatchUpdates
没有动画UICollectionView
。我发现此方法对我而言更好,collectionView.reloadData()
因为它减少了插入记录时的单元交换。
func appendCollectionView(numberOfItems count: Int){
// calculate indexes for the items to be added
let firstIndex = dataItems.count - count
let lastIndex = dataItems.count - 1
var indexPaths = [IndexPath]()
for index in firstIndex...lastIndex {
let indexPath = IndexPath(item: index, section: 0)
indexPaths.append(indexPath)
}
UIView.performWithoutAnimation {
self.collectionView.performBatchUpdates({ () -> Void in
self.collectionView.insertItems(at: indexPaths)
}, completion: { (finished) -> Void in
})
}
}
- (void)reloadCollectionViewAnimated:(BOOL)animated {
if (animated) {
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:^(BOOL finished) {
}];
} else {
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
[CATransaction commit];
}
}
只需增加我的0.02美元,我就尝试了所选答案的两个版本,并且原始方式可以更好地达到我的目的。我正在使用一个无限滚动的日历视图,该视图允许用户在给定的星期输入日历,然后来回滑动并选择单个日期以过滤列表。
在我的实现中,为了使事情在较旧的设备上保持高性能,代表日历视图的日期数组必须保持相对较小,这意味着要保留大约5周的日期,而用户要在第3周居中。使用第二种方法的问题是,还有第二个步骤,您必须在没有动画的情况下将集合视图滚动回到中间,这会由于某种原因而使基本动画被阻止,从而使外观非常参差不齐。
我的代码:
[UIView setAnimationsEnabled:NO];
[self.collectionView performBatchUpdates:^{
[self.collectionView deleteItemsAtIndexPaths:indexPathDeleteArray];
[self.collectionView insertItemsAtIndexPaths:indexPathAddArray];
} completion:NULL];
[UIView setAnimationsEnabled:YES];
NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:14 inSection:0];
[self.collectionView scrollToItemAtIndexPath:newIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];
func reloadRowsWithoutAnimation(at indexPaths: [IndexPath]) {
let contentOffset = collectionView.contentOffset
UIView.setAnimationsEnabled(false)
collectionView.performBatchUpdates {
collectionView.reloadItems(at: indexPaths)
}
UIView.setAnimationsEnabled(true)
collectionView.setContentOffset(contentOffset, animated: false)
}