web-dev-qa-db-fra.com

Évitez l'animation de UICollectionView après reloadItemsAtIndexPaths

UICollectionView animer des éléments après que reloadItemsAtIndexPaths est appelé (animation en fondu).

Y a-t-il un moyen d'éviter cette animation?

iOS 6

80
Marcin

Vous pouvez aussi essayer ceci:

UICollectionView *collectionView;

...

[UIView setAnimationsEnabled:NO];

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

Modifier:

J'ai également constaté que si vous enveloppez performBatchUpdates dans un bloc d'animation UIView, l'animation UIView est utilisée à la place de l'animation par défaut. Vous pouvez donc définir la durée de l'animation sur 0, comme suit:

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

C'est super cool si vous voulez utiliser les animations élastiques d'iOS 7 pendant les insertions et les suppressions!

152
Sam

Notez que si vous ciblez iOS 7 ou supérieur, vous pouvez utiliser la nouvelle méthode UIViewperformWithoutAnimation:. Je suppose que sous le capot, cela correspond à peu près aux autres réponses ici (désactivation temporaire de UIView animations/actions Core Animation), mais la syntaxe est agréable et nette.

Donc, pour cette question en particulier ...

Objective-C:

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


Swift:

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


Bien sûr, ce principe peut être appliqué à toute situation dans laquelle vous souhaitez vous assurer qu'un changement est pas animé .

197
Stuart

UICollectionView animer des éléments après que reloadItemsAtIndexPaths est appelé (animation en fondu).

Y a-t-il un moyen d'éviter cette animation?

iOS 6

Je suppose que vous utilisez un FlowLayout. Puisque vous essayez de vous débarrasser de l'animation de fondu, essayez ceci:

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
    }

}

C'est une question très ancienne, vous ne ciblez donc probablement plus iOS 6. Personnellement, je travaillais sur tvOS 11 et je posais la même question. C’est donc ici pour tous ceux qui ont le même problème.

10
Matt Mc

J'ai écrit un catégorie sur UICollectionView pour le faire. L'astuce consiste à désactiver toutes les animations lors du rechargement:

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

[self reloadItemsAtIndexPaths:indexPaths];

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

Voici une version de Swift 3 à performBatchUpdates sans animation à un UICollectionView. _. J'ai trouvé que cela fonctionnait mieux pour moi que collectionView.reloadData() parce que cela réduisait l'échange de cellules lorsque des enregistrements étaient insérés.

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

        })
    }
}
4
markhorrocks
- (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
Peter Lapisu

Juste pour ajouter mon 0,02 $, j'ai essayé les deux versions de la réponse sélectionnée, et la méthode originale a mieux fonctionné pour mes besoins. Je travaille sur une vue de calendrier défilant à l'infini qui permet à un utilisateur d'entrer dans le calendrier une semaine donnée, puis de faire glisser votre doigt et de sélectionner des jours individuels pour le filtrage d'une liste.

Dans mon implémentation, afin de conserver les performances sur les appareils plus anciens, le tableau de dates représentant la vue du calendrier doit être relativement petit, ce qui signifie qu’il faut conserver environ 5 semaines de dates, l’utilisateur étant au centre à la 3e semaine. Le problème avec l'utilisation de la deuxième approche est qu'il existe une deuxième étape dans laquelle vous devez faire défiler la vue de collection au milieu sans animation, ce qui donne une apparence très irrégulière pour une raison quelconque avec l'animation de base bloquée.

Mon code:

[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];
1
Matt S.
extension UICollectionView {
    func reloadWithoutAnimation(){
        CATransaction.begin()
        CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
        self.reloadData()
        CATransaction.commit()
    }
}
0
Amjad Tubasi