Избегайте анимации UICollectionView после reloadItemsAtIndexPaths


UICollectionView анимировать элементы после reloadItemsAtIndexPaths называется (fade animation).

есть ли способ избежать этой анимации?

iOS 6

8 72

8 ответов:

вы также можете попробовать это:

UICollectionView *collectionView;

...

[UIView setAnimationsEnabled:NO];

[collectionView performBatchUpdates:^{
    [collectionView reloadItemsAtIndexPaths:indexPaths];
} completion:^(BOOL finished) {
    [UIView setAnimationsEnabled:YES];
}];

Edit:

Я также обнаружил, что если вы оборачиваете performBatchUpdates в блоке анимации UIView анимация UIView используется вместо анимации по умолчанию, поэтому вы можете просто установить длительность анимации в 0, например:

[UIView animateWithDuration:0 animations:^{
    [collectionView performBatchUpdates:^{
        [collectionView reloadItemsAtIndexPaths:indexPaths];
    } completion:nil];
}];

это очень круто, если вы хотите использовать iOS 7 пружинистые анимации во время вставки и удаления!

стоит отметить, что если вы нацелены на iOS 7 и выше, вы можете использовать новый UIView метод performWithoutAnimation:. Я подозреваю, что под капотом это делает почти то же самое, что и другие ответы здесь (временное отключение UIView анимация / основные действия анимации), но синтаксис хороший и чистый.

Итак, для этого вопроса в особый...

Цель-C:

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


Swift:

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


Конечно, этот принцип может быть применен для любой ситуации, которую вы хотите обеспечить изменение не анимация.

Я написал категория на UICollectionView сделать это. Фокус в том, чтобы отключить все анимации при перезагрузке:

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

[self reloadItemsAtIndexPaths:indexPaths];

if (!animated) {
    [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];

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 и имел тот же вопрос, поэтому это вот для тех, кто приходит с той же проблемой.

extension UICollectionView {
    func reloadWithoutAnimation(){
        CATransaction.begin()
        CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
        self.reloadData()
        CATransaction.commit()
    }
}