96

UICollectionView 在调用 reloadItemsAtIndexPaths 之后为项目设置动画(淡入淡出动画)。

有没有办法避免这个动画?

iOS 6

4

10 回答 10

248

值得注意的是,如果你的目标是 iOS 7 及以上,你可以使用新UIView方法performWithoutAnimation:。我怀疑在后台这与此处的其他答案(暂时禁用UIView动画/核心动画操作)大致相同,但语法很好而且干净。

所以特别是对于这个问题......

目标-C:

[UIView performWithoutAnimation:^{
    [self.collectionView reloadItemsAtIndexPaths:indexPaths];
}];


迅速:

UIView.performWithoutAnimation {
    self.collectionView.reloadItemsAtIndexPaths(indexPaths)
}


当然,此原则可以应用于您希望确保更改被激活的任何情况。

于 2014-08-20T11:46:15.990 回答
163

你也可以试试这个:

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 弹性动画,这将非常酷!

于 2013-02-25T14:07:45.727 回答
22

UICollectionView 在调用 reloadItemsAtIndexPaths 之后为项目设置动画(淡入淡出动画)。

有没有办法避免这个动画?

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 上工作并且有同样的问题,所以这里是为任何遇到同样问题的人准备的。

于 2018-02-09T03:07:49.710 回答
8

在 UICollectionView 上写了一个类别来做到这一点。诀窍是在重新加载时禁用所有动画:

if (!animated) {
    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
}

[self reloadItemsAtIndexPaths:indexPaths];

if (!animated) {
    [CATransaction commit];
}
于 2013-01-19T10:56:37.333 回答
6
extension UICollectionView {
    func reloadWithoutAnimation(){
        CATransaction.begin()
        CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
        self.reloadData()
        CATransaction.commit()
    }
}
于 2017-01-03T07:02:35.857 回答
5

这是一个performBatchUpdates没有动画的 Swift 3 版本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

        })
    }
}
于 2017-05-31T09:46:08.260 回答
2
- (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];
    }

}
于 2014-01-25T16:54:33.213 回答
1

只是为了增加我的 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];
于 2014-06-08T01:56:42.757 回答
0
 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)
    }
于 2020-10-22T13:58:39.377 回答
0

而不是使用reloadData()以下尝试重新加载所有可见单元格而不使用动画。

self.collectionView.reloadItems(at: self.collectionView.indexPathsForVisibleItems)
于 2021-02-20T18:37:54.337 回答