Comment savoir si UICollectionView a été complètement chargé?

Je dois effectuer certaines opérations chaque fois que UICollectionView a été complètement chargé, c’est-à-dire qu’à ce moment-là, toutes les méthodes de données / layout de UICollectionView doivent être appelées. Comment puis-je le savoir? Existe-t-il une méthode déléguée pour connaître l’état chargé de UICollectionView?

// In viewDidLoad [self.collectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL]; - (void)observeValueForKeyPath:(NSSsortingng *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { // You will get here when the reloadData finished } - (void)dealloc { [self.collectionView removeObserver:self forKeyPath:@"contentSize" context:NULL]; } 

Cela a fonctionné pour moi:

 [self.collectionView reloadData]; [self.collectionView performBatchUpdates:^{} completion:^(BOOL finished) { /// collection-view finished reload }]; 

Swift 4 syntaxe:

 self.collectionView.reloadData() self.collectionView.performBatchUpdates(nil, completion: { (result) in // ready }) 

C’est en fait plutôt très simple.

Lorsque vous appelez par exemple la méthode reloadData de UICollectionView ou la méthode invalidateLayout de sa mise en page, procédez comme suit:

 dispatch_async(dispatch_get_main_queue(), ^{ [self.collectionView reloadData]; }); dispatch_async(dispatch_get_main_queue(), ^{ //your stuff happens here //after the reloadData/invalidateLayout finishes executing }); 

Pourquoi cela fonctionne:

Le thread principal (qui est l’endroit où nous devrions faire toutes les mises à jour de l’interface utilisateur) héberge la queue principale, qui est en série, c’est-à-dire qu’elle fonctionne en mode FIFO. Ainsi, dans l’exemple ci-dessus, le premier bloc est appelé et notre méthode reloadData est appelée, suivie de toute autre chose dans le deuxième bloc.

Maintenant, le thread principal bloque également. Donc, si vous reloadData prend 3s pour exécuter, le traitement du deuxième bloc sera différé par ces 3s.

Juste pour append une excellente réponse à @dezinezync:

Swift 3+

 collectionView.collectionViewLayout.invalidateLayout() // or reloadData() DispatchQueue.main.async { // your stuff here executing after collectionView has been layouted } 

Fais-le comme ça:

  UIView.animateWithDuration(0.0, animations: { [weak self] in guard let strongSelf = self else { return } strongSelf.collectionView.reloadData() }, completion: { [weak self] (finished) in guard let strongSelf = self else { return } // Do whatever is needed, reload is finished here // eg scrollToItemAtIndexPath let newIndexPath = NSIndexPath(forItem: 1, inSection: 0) strongSelf.collectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false) }) 

Cela fonctionne pour moi:

 __weak typeof(self) wself= self; [self.contentCollectionView performBatchUpdates:^{ [wself.contentCollectionView reloadData]; } completion:^(BOOL finished) { [wself pageViewCurrentIndexDidChanged:self.contentCollectionView]; }]; 

Voici comment j’ai résolu le problème avec Swift 3.0:

 override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if !self.collectionView.visibleCells.isEmpty { // stuff } } 

Def faire ceci:

 //Subclass UICollectionView class MyCollectionView: UICollectionView { //Store a completion block as a property var completion: (() -> Void)? //Make a custom funciton to reload data with a completion handle func reloadData(completion: @escaping() -> Void) { //Set the completion handle to the stored property self.completion = completion //Call super super.reloadData() } //Override layoutSubviews override func layoutSubviews() { //Call super super.layoutSubviews() //Call the completion self.completion?() //Set the completion to nil so it is reset and doesn't keep gettign called self.completion = nil } } 

Puis appelez comme ça dans votre VC

 let collection = MyCollectionView() self.collection.reloadData(completion: { }) 

Assurez-vous que vous utilisez la sous-classe!

J’avais besoin d’une action sur toutes les cellules visibles lorsque la vue de collection est chargée avant d’être visible par l’utilisateur, j’ai utilisé:

 public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if shouldPerformBatch { self.collectionView.performBatchUpdates(nil) { completed in self.modifyVisibleCells() } } } 

Faites attention à ce que cela sera appelé lors du défilement de la vue de collection, pour éviter cette surcharge, j’ai ajouté:

 private var souldPerformAction: Bool = true 

et dans l’action elle-même:

 private func modifyVisibleCells() { if self.shouldPerformAction { // perform action ... ... } self.shouldPerformAction = false } 

L’action sera toujours effectuée plusieurs fois, en tant que nombre de cellules visibles à l’état initial. mais sur tous ces appels, vous aurez le même nombre de cellules visibles (toutes). Et l’indicateur booléen l’empêche de fonctionner à nouveau après que l’utilisateur a commencé à interagir avec la vue de collection.

Vous pouvez faire comme ça …

  - (void)reloadMyCollectionView{ [myCollectionView reload]; [self performSelector:@selector(myStuff) withObject:nil afterDelay:0.0]; } - (void)myStuff{ // Do your stuff here. This will method will get called once your collection view get loaded. } 

Essaye ça:

 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return _Items.count; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewCell *cell; //Some cell stuff here... if(indexPath.row == _Items.count-1){ //THIS IS THE LAST CELL, SO TABLE IS LOADED! DO STUFF! } return cell; }