Уникайте анімації UICollectionView після reloadItemsAtIndexPaths


91

Викликається анімовані елементи UICollectionView після reloadItemsAtIndexPaths (анімація затухання).

Чи є спосіб уникнути цієї анімації?

iOS 6

Відповіді:


231

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

Тож щодо цього питання зокрема ...

Завдання-C:

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


Стрімкий:

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


Звичайно, цей принцип можна застосовувати до будь-якої ситуації, для якої ви хочете, щоб зміни не анімувались.


3
Це працювало краще, ніж прийнята відповідь для мене на iOS 7+.
Філіп Сабурін

Він вимикає всі анімації не тільки для перегляду колекції
user2159978

10
@ user2159978 Це правильно; всі відповіді тут тимчасово відключають анімацію UIView. Анімація вимкнена лише для дій, ініційованих із переданого блоку, у цьому випадку просто перезавантаження подання колекції. Це цілком слушна відповідь на запитання, тому я не думаю, що він заслуговує на голосування проти.
Стюарт

Неймовірне рішення. Використовуючи це замість animateWithDuration: 0, запобігає швидкому, але видимому збою макета при використанні саморозмірних комірок подання колекції без елемента Розмір
Етан Гілл

1
Це рішення вже не працює на iOS 14, всередині цього блоку я використовую reloadData, але з iOS 13 це спрацювало
Maray97

161

Ви також можете спробувати це:

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 під час вставки та видалення!


1
Дякую. Це було дуже корисно при додаванні таймерів секундоміра до комірок uicollectionview.
hatunike

Блискуче! Я використовував це з insertCells і з піднятою клавіатурою, щоб анімувати collectionView до нового зміщення після того, як була вставлена ​​комірка.
David H

5
Як каже Петро, ​​це заважає іншій анімації. Натомість вам слід зателефонувати [UIView setAnimationsEnabled: YES] поза блоком завершення. Таким чином ви запобігаєте лише цій анімації.
Adlai Holler

2
Я додав альтернативний метод, який робить точно те саме.
Сем

1
Загортання performBatchUpdatesвсередину animateWithDuration- блискуче! Дякуємо за підказку!
Роберт

19

Викликається анімовані елементи 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 і мав те саме запитання, тому це тут для тих, хто стикається з тією ж проблемою.


1
До цієї відповіді було 3 чи 4 коментарі до ефекту "Вау, це працює дуже добре!" Хтось вирішив видалити коментарі. Я думаю, фактично, це сучасний і невдалий спосіб зробити це, і ці коментарі були визнанням цього.
Метт Мак,

8

Я написав категорію на UICollectionView, щоб зробити саме це. Фокус полягає у відключенні всіх анімацій під час перезавантаження:

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

[self reloadItemsAtIndexPaths:indexPaths];

if (!animated) {
    [CATransaction commit];
}

Я також отримую відповідь від Apple, що це не повинно робити жодної анімації, якщо так, це помилка. Я не знаю, чи роблю я щось не так, чи це помилка.
Марсін

2
Ви також можете просто зробити це CATransaction.setDisableActions(true)як скорочення.
CIFilter


5

Ось версія 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

        })
    }
}

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];
    }

}

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];

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)
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.