ios objective-c xcode uicollectionview

ios - ¿Cómo defino el tamaño de un CollectionView al girar?



objective-c xcode (7)

Aquí están mis 2 centavos, porque los tamaños de tus artículos son estáticos, ¿por qué no configuras el tamaño de los artículos en el collectionViewLayout ?

Será más rápido hacer esto en lugar de esperar que la vista de colección llame a su método de delegado para cada celda.

viewWillLayoutSubviews se puede utilizar para detectar la rotación en los controladores de vista. invalidateLayout puede usarse en un diseño de vista de colección para forzarlo a preparar el diseño nuevamente, lo que hace que posicione los elementos con los nuevos tamaños en este caso.

- (void)viewWillLayoutSubviews; { [super viewWillLayoutSubviews]; UICollectionViewFlowLayout *flowLayout = (id)self.firstCollectionView.collectionViewLayout; if (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) { flowLayout.itemSize = CGSizeMake(170.f, 170.f); } else { flowLayout.itemSize = CGSizeMake(192.f, 192.f); } [flowLayout invalidateLayout]; //force the elements to get laid out again with the new size }

edición: actualizado con el ejemplo Swift2.0

override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { return } if UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) { flowLayout.itemSize = CGSize(width: 170, height: 170) } else { flowLayout.itemSize = CGSize(width: 192, height: 192) } flowLayout.invalidateLayout() }

Tengo un controlador de vista con 2 controladores CollectionView.

Me gustaría en la rotación que solo una de las vistas de colección cambie de tamaño a un tamaño personalizado, mientras que la otra sigue siendo la misma.

He intentado usar:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { // Adjust cell size for orientation if (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) { return CGSizeMake(170.f, 170.f); } return CGSizeMake(192.f, 192.f); }

Sin embargo eso solo cambia ambas vistas de colección. ¿Cómo consigo que sea específico para una sola colección?


Con la nueva API desde iOS 8 estoy usando:

Swift 3:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) updateCollectionViewLayout(with: size) } private func updateCollectionViewLayout(with size: CGSize) { if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout { layout.itemSize = (size.width < size.height) ? itemSizeForPortraitMode : itemSizeForLandscapeMode layout.invalidateLayout() } }

C objetivo:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator { [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; [self updateCollectionViewLayoutWithSize:size]; } - (void)updateCollectionViewLayoutWithSize:(CGSize)size { UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout; layout.itemSize = (size.width < size.height) ? itemSizeForPortraitMode : itemSizeForLandscapeMode; [layout invalidateLayout]; }


He manejado esto detectando el cambio de orientación en el método setBounds: . UICollectionView y setBounds: método setBounds: (ver más abajo). En flowLayoutForGallerySize creamos un nuevo UICollectionViewFlowLayout con diferentes espacios y itemSize dependiendo del tamaño de la vista de colección.

- (void)setBounds:(CGRect)bounds { // detect orientation changes and update itemSize in the flow layout CGSize oldSize = self.bounds.size; [super setBounds:bounds]; BOOL wasLandscape = (oldSize.width > oldSize.height); BOOL nowLandscape = (bounds.size.width > bounds.size.height); if (wasLandscape != nowLandscape) { // create a new flow layout object for the new gallery size self.flowLayout = [self flowLayoutForGallerySize:bounds.size]; // change to the new flow layout [self setCollectionViewLayout:self.flowLayout animated:NO]; DLog(@"orientation change to %@", NSStringFromCGSize(bounds.size)); } }


La pregunta era, cómo separar dos vistas de colección en sizeForItemAtIndexPath. ¿Por qué no algo como esto?

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { if collectionView == firstCollectionView{ return CGSize(width: self.frame.width/3, height: 40) } else if collectionView == secondCollectionView{ return CGSize(width: self.frame.width, height: self.frame.height-2) } abort() }


Puedes cambiar tu sentencia if. Necesitará tener una referencia a las vistas de colección.

if (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) && collectionView == self.firstCollectionView) { return CGSizeMake(170.f, 170.f); }


Resolví este problema comprobando la rotación del dispositivo y luego volviendo a cargar el diseño. Comprobando el tamaño de la pantalla y utilizando este tamaño para mostrar mi celda.

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { //get new width of the screen screenRect = [[UIScreen mainScreen] bounds]; screenWidth = screenRect.size.width; //if landscape mode if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) { screenDivide = 5; } else { screenDivide = 3; } //reload the collectionview layout after rotating UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout; [layout invalidateLayout]; }

Entonces definí las celdas así.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath { screenRect = [[UIScreen mainScreen] bounds]; screenWidth = screenRect.size.width; CGSize elementSize = CGSizeMake(screenWidth/screenDivide, 100); return elementSize; }


La respuesta verificada no es eficiente

El problema : invalidar el diseño en viewWillLayoutSubviews () es un trabajo pesado. viewWillLayoutSubviews () se llama varias veces cuando se crea una instancia de ViewController .

Mi solución (Swift) : incruste la manipulación de su tamaño en UICollectionViewDelegateFlowLayout .

// Keep a local property that we will always update with the latest // view size. var updatedSize: CGSize! // Use the UICollectionViewDelegateFlowLayout to set the size of our // cells. func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { // We will set our updateSize value if it''s nil. if updateSize == nil { // At this point, the correct ViewController frame is set. self.updateSize = self.view.frame.size } // If your collectionView is full screen, you can use the // frame size to judge whether you''re in landscape. if self.updateSize.width > self.updateSize.height { return CGSize(width: 170, 170) } else { return CGSize(width: 192, 192) } } // Finally, update the size of the updateSize property, every time // viewWillTransitionToSize is called. Then performBatchUpdates to // adjust our layout. override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) self.updateSize = size self.collectionView!.performBatchUpdates(nil, completion: nil) }