ios uicollectionview ios10 uicollectionviewlayout

Error de iOS 10: UICollectionView recibió atributos de diseño para una celda con una ruta de índice que no existe



ios10 uicollectionviewlayout (18)

Cuando tenga un diseño personalizado, recuerde borrar el caché (UICollectionViewLayoutAttributes) mientras anula la función de preparación

override func prepare() { super.prepare() cache.removeAll() }

Al ejecutar mi aplicación en un dispositivo con iOS 10, aparece este error:

UICollectionView recibió atributos de diseño para una celda con una ruta de índice que no existe

En iOS 8 y 9 funciona bien. He estado investigando y he descubierto que es algo relacionado con invalidar el diseño de la vista de colección. Traté de implementar esa solución sin éxito, por lo que me gustaría pedir ayuda directa. Esta es mi vista de jerarquía:

->Table view ->Each cell of table is a custom collection view [GitHub Repo][1] ->Each item of collection view has another collection view

Lo que he intentado es insertar

[self.collectionView.collectionViewLayout invalidateLayout];

En el

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView

de ambas vistas de colección.

También he tratado de invalidar el diseño antes de hacer una recarga de datos, no funciona ...

¿Alguien podría darme algunas instrucciones para tomar?


Después de pasar dos días de tiempo, el siguiente código resolvió el problema. Antes de cargar una vista de colección, escriba el siguiente código.

flowLayout.itemSize = CGSize(width: 92, height: 100)

Luego, el bloqueo se resolverá, pero encontrará un problema en las celdas de la vista de colección, ya que las celdas están comprimidas o no según su diseño. Luego solo una línea de código después de la línea de dirección de desplazamiento

override func prepareForReuse() { super.prepareForReuse() imagesCollectionHeight.constant = 100 // changing collectionview height constant imageContainerWidth.constant = 100 //changing width constant of some view self.layoutIfNeeded() // this line did the trick for me }

Con la línea de código anterior, puede ajustar su diseño de celda de vista de colección.

Espero que ayude a alguien.


En mi caso, estaba cambiando la constante NSlayoutConstraint

self.collectionViewContacts.collectionViewLayout.invalidateLayout() UIView.animate(withDuration: 0.3) { self.view.layoutIfNeeded() } self.collectionViewContacts.reloadData()

resuelto el problema


En mi caso, estaba cambiando la constante de NSLayoutConstraint, ninguna de las soluciones anteriores funcionó para mí. gracias a @jeff ayan cuya respuesta me dio la pista. Resolví el problema con este código

[self.collectionView reloadData]; [self.collectionView layoutIfNeeded];

Espero que ayude a alguien


Esto me sucedió cuando el número de celdas en collectionView cambió. Resulta que me faltaba invalidateLayout después de llamar a reloadData. Después de agregarlo, no he experimentado más bloqueos. Apple ha realizado algunas modificaciones en collectionViews en iOS10. Supongo que esa es la razón por la que no estamos experimentando el mismo problema en versiones anteriores.

Aquí está mi código final:

[self.collectionView reloadData]; [self.collectionView.collectionViewLayout invalidateLayout];


Esto también me sucedió a mí, pero fue porque mi UICollectionViewDataSource cambió, y no llamé a -[UICollectionView reloadData] . En mi caso, tenía la siguiente estructura de datos:

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { if (collectionView == self.fooCollectionView) { self.selectedFoo = self.foos[indexPath.row]; [self.barCollectionView reloadData]; self.fooCollectionView.hidden = YES; self.barCollectionView.hidden = NO; } else if (collectionView == self.barCollectionView) { // do some stuff with the selected bar self.selectedFoo = nil; // This -reloadData call fixed my error. I thought I didn''t // need it since my UICollectionView was hidden [self.barCollectionView reloadData]; self.barCollectionView.hidden = YES; self.fooCollectionView.hidden = NO; } }

Tenía dos UICollectionView s: uno para Foo s y otro para Bar s. En mi -collectionView:didSelectItemAtIndexPath: tuve lo siguiente:

let flowLayout = UICollectionViewFlowLayout() flowLayout.scrollDirection = .horizontal collecView.collectionViewLayout = flowLayout collecView.delegate = self collecView.dataSource = self collecView.reloadData()

Sin la llamada -reloadData , vería el bloqueo cuando gire el dispositivo.


La respuesta anterior ayuda, pero si usa celdas de tamaño automático, su tamaño será incorrecto.

UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init]; layout.estimatedItemSize = CGSizeMake(60, 25); layout.itemSize = UICollectionViewFlowLayoutAutomaticSize; self.collectionView.collectionViewLayout = layout;

Resuelvo estos problemas reemplazando

[self.collectionView reloadData];

a

[self.collectionView reloadSections:indexSet];


La respuesta de @ Katrin ayudó mucho, pero pude lograr mejores resultados agregando una línea más:

collectionView.reloadData() collectionView.collectionViewLayout.invalidateLayout() collectionView.layoutSubviews() // <-- here it is :)

Ahora no puedo decir si podría reproducir el bloqueo con esta línea o no, pero supongo que hubo una ... Entonces, todavía no es una bala de plata, sino algo.


Llamar invalidateLayout no evitó el bloqueo en mi caso. (Funcionó si el número de elementos en la vista de colección aumentaba pero no si disminuía). Contexto: tengo un UICollectionView dentro de un UITableViewCell y cuando la celda de la tabla se reutiliza restablezco los delegados de la colección. Solucioné el problema no invalidando la memoria caché, sino RECREANDO el objeto de diseño cada vez que restablezco el delegado, luego llamé a reloadData ():

foo.dataSource = newDataSource foo.delegate = newDelegate foo.fixLayoutBug() foo.reloadData() func fixLayoutBug() { let oldLayout = collectionViewLayout as! UICollectionViewFlowLayout let newLayout = UICollectionViewFlowLayout() newLayout.estimatedItemSize = oldLayout.estimatedItemSize newLayout.footerReferenceSize = oldLayout.footerReferenceSize newLayout.headerReferenceSize = oldLayout.headerReferenceSize newLayout.itemSize = oldLayout.itemSize newLayout.minimumInteritemSpacing = oldLayout.minimumInteritemSpacing newLayout.minimumLineSpacing = oldLayout.minimumLineSpacing newLayout.scrollDirection = oldLayout.scrollDirection newLayout.sectionFootersPinToVisibleBounds = oldLayout.sectionFootersPinToVisibleBounds newLayout.sectionHeadersPinToVisibleBounds = oldLayout.sectionHeadersPinToVisibleBounds newLayout.sectionInset = oldLayout.sectionInset newLayout.sectionInsetReference = oldLayout.sectionInsetReference collectionViewLayout = newLayout }


Lo siguiente lo hizo para mí:

[self.collectionView reloadData]; [self.collectionView layoutIfNeeded];

Este código parece obligar a collectionView a desplazarse a la primera celda antes de volver a cargar los datos, lo que parece causar el error en mi caso.


Me enfrenté al problema similar mientras mostraba-ocultaba la vista de colección usando el cambio animado de restricciones. Mi solución se basa en las respuestas existentes.

struct Bar { let name: String } struct Foo { let name: String; let bars: [Bar] }


No es lo mejor reloadData cada vez (debe usar insertItems y deleteItems, e incluso reloadSections). Pero ... después de decir que en algunos casos es válido, puedes hacer esto:

collectionView.dataSource = nil collectionView.delegate = nil /*... All changes here. ... */ collectionView.dataSource = self collectionView.delegate = self collectionView.reloadData()


Restablecer el diseño de UICollectionView me resolvió el problema:

let layout = UICollectionViewFlowLayout() collectionView?.collectionViewLayout = layout


Si desea mantener su posición de desplazamiento y corregir el bloqueo, puede usar esto:

collectionView.reloadData() let context = collectionView.collectionViewLayout.invalidationContext(forBoundsChange: collectionView.bounds) context.contentOffsetAdjustment = CGPoint.zero collectionView.collectionViewLayout.invalidateLayout(with: context)


También enfrenté este problema con 2 collectionViews en la misma vista porque agregué el mismo UICollectionViewFlowLayout en ambas colecciones:

let layout = UICollectionViewFlowLayout() collectionView1.collectionViewLayout = layout collectionView2.collectionViewLayout = layout

Por supuesto, se bloquea al recargar los datos si collectionView1 Data cambia. Si esto pudiera ayudar a alguien.


Tuve el problema al usar RxDataSources con RxCollectionViewSectionedAnimatedDataSource y lo resolví combinando dos respuestas. Tengo que invalidateLayout() cuando recargo reactivamente mi colección:

... .asDriver(onErrorJustReturn: []) .do(onNext: { [weak self] _ in DispatchQueue.main.async { self?.collectionViewLayout.invalidateLayout() self?.collectionView.layoutSubviews() } }).drive(collectionView.rx.items(dataSource: collectionController.dataSource)) .disposed(by: disposeBag)

y borrar la (s) matriz (s) de cache en el método de diseño prepare() . Aquí está el código:

override func prepare() { super.prepare() cache.removeAll() guard let collectionView = collectionView, collectionView.numberOfSections > 0, let delegate = delegate else { return } ...


Yo tuve este problema también. En mi caso, se aplicó un UICollectionViewLayout personalizado a la vista de recopilación y el problema era que tenía datos obsoletos para la cantidad de celdas que deberían mostrarse. Eso es definitivamente algo que puede verificar cuando vea los UICollectionView received layout attributes for a cell with an index path that does not exist


reloadData() resolver esto recreando la collectionViewLayout antes de llamar a reloadData()

El problema probablemente se relacionó con que tengo una instancia separada para dataSource (es decir, no el controlador de vista que contiene el collectionView), y al intercambiar la fuente de datos, podría aparecer el bloqueo.