Anidado UICollectionViews, AutoLayout y rotation en iOS 8

Comencé a usar AutoLayout para un proyecto grande y me sorprendió positivamente. Sin embargo, ahora tengo que ajustar el proyecto para adaptarse a las classs de rotation y tamaño, y tengo grandes problemas para que las vistas se comporten correctamente.

El problema básico es que tengo UICollectionViews con celdas que contienen de nuevo UICollectionViews . Cuando el dispositivo se gira, la vista de la colección base se adapta a las celdas correctas, pero todas las celdas de las vistas de la colección anidada no se ajustan automáticamente al tamaño nuevo.

Después de la investigación se trata de:

  • Cuando se llama a viewWillTransitionToSize , la vista de la colección base aún no gira (como se esperaba)
  • Algún time después de que se llama a viewDidLayoutSubviews, la vista de la colección base ahora tiene el tamaño rotado, pero lamentablemente sus celdas aún no, todavía tienen el ancho como ANTES de la rotation
  • Incluso en el coordinator animateAlongsideTransition ... completion:{} bloque en viewWillTransitionToSize las celdas aún no tienen su nuevo ancho.

Lo anterior significa que no hay lugar donde pueda hacer posible que las celdas de las vistas de la colección anidada cambien de tamaño, ya que todavía no conozco los nuevos anchos; y el sistema de reproducción automática no los ajusta automáticamente.

¿Alguien más tiene el mismo problema o conoce una solución?

Respondiendo a mi propia pregunta aquí, finalmente encontré la solución. Para cualquier otro que tenga problemas con esto aquí es lo que hice:

La parte principal radica en poner las llamadas invalidateLayout y reloadData en los lugares correctos:

  • Coloque un invalidateLayout en el layout de la willTransitionToSize en la function willTransitionToSize .
  • Coloque una reloadData en la colección reloadData en el bloque de finalización de un coordinator animateAlongsideTransition: llame a la function willTransitionToSize .
  • Asegúrese de que las restricciones de reproducción automática para cualquier vista de las celdas estén configuradas a la derecha: conecté la vista de celda con restricciones de reproducción automática a la vista de contenido de la celda en el código.
  • En caso de prepareLayout function prepareLayout del layout de vista de colección, asegúrese de que los tamaños de celda precalculados usan el ancho correcto, aquí usé un ancho incorrecto que conlleva algunos problemas adicionales.

Gracias a TheEye. Quería agregar esto como un comentario a su respuesta, pero al parecer no tengo suficiente Karma (todavía), así que considera esto un addendum.

Tenía el mismo problema, pero las celdas en mi colección de ilustraciones tienen un "estado expandido" cuando se seleccionan. si el usuario rota el dispositivo y llamamos [self.collectionview reloadData] , cualquier celda que esté expandida perderá su estado. Opcionalmente puede llamar a performBatchUpdates y forzar la vista de colección a la presentación sin perder el estado de ninguna celda

 -(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator{ [self.collectionView.collectionViewLayout invalidateLayout]; [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) { } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) { //[self.collectionView reloadData];//this works but reloading the view collapses any expanded cells. [self.collectionView performBatchUpdates:nil completion:nil]; }]; } 

La respuesta de TheKey es correcta. Sin embargo, en lugar de volver a cargar los datos, puede llamar

 UICollectionView.collectionViewLayout:finalizeCollectionViewUpdates() 

Ejemplo:

 override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { self.collectionView.collectionViewLayout.invalidateLayout() self.collectionView.collectionViewLayout.finalizeCollectionViewUpdates() } 

Quería ofrecer una solución alternativa. No me gustó la ligera demora en llamar a reloadData o performBatchUpdates en la finalización de la animation del coordinador. Ambos también resultaron en advertencias de AutoLayout.

Dentro de viewWillTransitionToSize, invoca invalidateLayout en todas las vistas de colección anidadas visibles y finalmente invoca invalidateLayout en la vista de colección de nivel superior / superior.

Mi celda de vista de colección que tiene una vista de colección secundaria:

 class NestableCollectionViewCell: UICollectionViewCell { @IBOutlet weak var collectionView: NestableCollectionView? } 

Extensión de UICollectionView para invalidar vistas de colección anidadas:

 class NestableCollectionView: UICollectionView { func invalidateNestedCollectionViews(){ let visibleCellIndexPaths = self.indexPathsForVisibleItems() for cellIndex in visibleCellIndexPaths { if let nestedCell = self.cellForItemAtIndexPath(cellIndex) as? NestableCollectionViewCell { // invalidate any child collection views nestedCell.collectionView?.invalidateNestedCollectionViews() // finally, invalidate the cell's own collection view nestedCell.collectionView?.collectionViewLayout.invalidateLayout() } } } } 

Y, invalidate on willTransitionToSize:

 override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) self.collectionView.invalidateNestedCollectionViews() self.collectionView.collectionViewLayout.invalidateLayout() }