collection uicollectionview delegates reload

¿Cómo sé que el UICollectionView se ha cargado completamente?



collection view swift 4 (12)

Tengo que hacer alguna operación cada vez que UICollectionView se haya cargado por completo, es decir, en ese momento se deben llamar todos los métodos de fuente de datos / diseño de UICollectionView. ¿¿Cómo sé eso?? ¿Hay algún método de delegado para conocer el estado cargado de UICollectionView?


Así es como resolví el problema con Swift 3.0:

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


Como respondió dezinezync , lo que necesita es enviar a la cola principal un bloque de código después de reloadData desde un UITableView o UICollectionView , y luego este bloque se ejecutará después de que las celdas se reloadData de la cola.

Para hacer esto más directo al usarlo, usaría una extensión como esta:

extension UICollectionView { func reloadData(_ completion: @escaping () -> Void) { reloadData() DispatchQueue.main.async { completion() } } }

También se puede implementar en un UITableView también


Def hacer esto:

//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 } }

Entonces llama así dentro de tu CV

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

Asegúrese de que está utilizando la subclase!


En realidad es bastante simple.

Cuando, por ejemplo, llama al método reloadData de UICollectionView o al método invalidateLayout de su diseño, haga lo siguiente:

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

Por qué esto funciona:

El hilo principal (que es donde deberíamos hacer todas las actualizaciones de la interfaz de usuario) aloja la cola principal, que es de naturaleza serial, es decir, funciona de la manera FIFO. Entonces, en el ejemplo anterior, se llama al primer bloque, que tiene reloadData nuestro método reloadData , seguido de cualquier otra cosa en el segundo bloque.

Ahora el hilo principal está bloqueando también. Entonces, si está reloadData toma 3s para ejecutarse, el procesamiento del segundo bloque será diferido por esos 3s.


Esto funcionó para mí:

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

Sintaxis de Swift 4:

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


Esto funciona para mí:

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


Hazlo asi:

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 // e.g. scrollToItemAtIndexPath let newIndexPath = NSIndexPath(forItem: 1, inSection: 0) strongSelf.collectionView.scrollToItemAtIndexPath(newIndexPath, atScrollPosition: UICollectionViewScrollPosition.Left, animated: false) })


Necesitaba que se realizara alguna acción en todas las celdas visibles cuando la vista de colección se carga antes de que sea visible para el usuario, usé:

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

Preste atención a que esto se activará cuando se desplace por la vista de colección, por lo que para evitar esta sobrecarga, agregué:

private var souldPerformAction: Bool = true

y en la propia acción:

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

La acción se seguirá realizando varias veces, como el número de celdas visibles en el estado inicial. pero en todas esas llamadas, tendrá el mismo número de celdas visibles (todas ellas). Y la bandera booleana evitará que se ejecute nuevamente después de que el usuario comience a interactuar con la vista de colección.


Prueba esto:

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


Puedes hacer así ...

- (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. }


Sólo para agregar a una gran respuesta @dezinezync:

Swift 3+

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


// In viewDidLoad [self.collectionView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionOld context:NULL]; - (void)observeValueForKeyPath:(NSString *)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]; }