2012-11-25 9 views
98

Sto utilizzando uno UICollectionView con UICollectionViewFlowLayout.Modifica la dimensione di UICollectionViewCell su diversi orientamenti del dispositivo

io impostare la dimensione di ciascuna cella attraverso il

collectionView:layout:sizeForItemAtIndexPath: 

Quando si passa da verticale ad orizzontale, desidero regolare la dimensione di ciascuna cella per rientrare completamente la dimensione della CollectionView, senza lasciare spazio imbottitura tra le cellule.

Domande:

1) Come modificare le dimensioni di una cella dopo un evento di rotazione?

2) E, ancora meglio, come rendere il layout in cui le celle si adattano sempre all'intera dimensione dello schermo?

+0

di followben è attualmente accettato uno, ma ha alcuni problemi: sarà lanciare un errore console e l'animazione per il nuovo formato non accadrà correttamente. Vedi la mia risposta per la corretta implementazione. – memmons

+0

@ MichaelG.Emmons: la risposta funzionerà meglio dove una vista raccolta visualizza solo una singola cella a dimensione intera alla volta. In tal caso, ha senso che UIKit si lamenta di rotazione poiché eseguirà una query su 'sizeForItemAtIndexPath' prima di chiamare' didRotateFromInterfaceOrientation'. Tuttavia, per una vista di insieme con più celle sullo schermo, invalidare il layout prima della rotazione provoca un brutto, visibile salto di dimensioni prima che la vista ruota. In questo caso, credo che la mia risposta sia ancora l'implementazione più corretta. – followben

+0

@followben D'accordo che ognuno ha i suoi problemi in diversi casi d'uso. In questo caso, però, l'OP indica 'Vorrei regolare la dimensione di ogni cella in ** completamente adatta alla dimensione di CollectionView **' che è esattamente la soluzione proposta nella mia risposta. Se potessi includere la mia soluzione nella tua risposta e prendere nota di quale approccio funziona meglio in quali condizioni sarebbe abbastanza buono per me. – memmons

risposta

198

1) È possibile mantenere e scambiare più oggetti di layout, ma c'è un modo più semplice. Basta aggiungere la seguente al vostro UICollectionViewController sottoclasse e regolare le dimensioni come richiesto:

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

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation 
{ 
    [self.collectionView performBatchUpdates:nil completion:nil]; 
} 

Calling -performBatchUpdates:completion: invalidando il layout e ridimensionare le celle con animazione (si può semplicemente passare zero a entrambi i params blocco se hai senza supplemento regolazioni da eseguire).

2) Invece di codificare le dimensioni degli articoli in -collectionView:layout:sizeForItemAtIndexPath, è sufficiente dividere l'altezza o la larghezza dei limiti di collectionView in base al numero di celle che si desidera inserire sullo schermo. Usa l'altezza se la tua collezioneView scorre in orizzontale o la larghezza se scorre verticalmente.

+0

Anche la soluzione proposta da Fiveagle funziona, ma questa è la soluzione che ho preferito. – Fmessina

+0

Come si gestisce la modifica dell'orientamento mentre la messa a fuoco è su un altro controller della vista, quindi la messa a fuoco viene riportata al controller della vista originale. Attualmente le mie cellule mantengono le dimensioni determinate dall'orientamento in cui sono state lasciate ma il nuovo orientamento. –

+0

nm, ho appena richiamato [self.collectionView performBatchUpdates: nil completion: nil]; durante viewDidAppear –

13

Ho risolto utilizzando due UICollectionViewFlowLayout. Uno per il ritratto e uno per il paesaggio. Ho assegnarli al mio CollectionView dinamicamente in -viewDidLoad

self.portraitLayout = [[UICollectionViewFlowLayout alloc] init]; 
self.landscapeLayout = [[UICollectionViewFlowLayout alloc] init]; 

UIInterfaceOrientation orientationOnLunch = [[UIApplication sharedApplication] statusBarOrientation]; 

if (UIInterfaceOrientationIsPortrait(orientationOnLunch)) { 
    [self.menuCollectionView setCollectionViewLayout:self.portraitLayout]; 
} else { 
    [self.menuCollectionView setCollectionViewLayout:self.landscapeLayout]; 
} 

Poi ho semplicemente modificato il mio Metodi collectionViewFlowLayoutDelgate come questo

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{ 
    CGSize returnSize = CGSizeZero; 

    if (collectionViewLayout == self.portraitLayout) { 
     returnSize = CGSizeMake(230.0, 120.0); 
    } else { 
     returnSize = CGSizeMake(315.0, 120.0); 
    } 

    return returnSize; 
} 

Ultimo passo da un layout a un altro a rotazione

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{ 
    if (UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) { 
     [self.menuCollectionView setCollectionViewLayout:self.landscapeLayout animated:YES]; 
    } else { 
     [self.menuCollectionView setCollectionViewLayout:self.portraitLayout animated:YES]; 
    } 
} 
+0

Grazie !! Proverò la tua soluzione più tardi e ti farò sapere. – Fmessina

34

Se non si desidera aggiungere animazioni aggiuntive da performBatchUpdates:completion:, è sufficiente utilizzare invalidateLayout per forzare il caricamento di ViewViewayout.

- (void)viewWillLayoutSubviews 
{ 
    [super viewWillLayoutSubviews]; 
    [self.collectionView.collectionViewLayout invalidateLayout]; 
} 
8

C'è un modo semplice per impostare la raccolta dimensioni di visualizzazione delle cellule:

UICollectionViewFlowLayout *layout = (id) self.collectionView.collectionViewLayout; 
layout.itemSize = CGSizeMake(cellSize, cellSize); 

Non sono sicuro se è animatable però.

+0

ho dovuto usare questo all'interno di viewWillLayoutSubviews con la risposta di Hai Feng Kao: http://stackoverflow.com/a/14776915/2298002 – greenhouse

2

Se si utilizza autolayout. È sufficiente disporre di invalidate layout nel controller di visualizzazione durante la rotazione e regolare offset nella sottoclasse del layout di flusso.

Così, nel vostro controller della vista -

override func willRotateToInterfaceOrientation(toInterfaceOrientation:  UIInterfaceOrientation, duration: NSTimeInterval) { 
    self.galleryCollectionView.collectionViewLayout.invalidateLayout() 
} 

E nel tuo FlowLayout Subclass

override func prepareLayout() { 
    if self.collectionView!.indexPathsForVisibleItems().count > 0{ 
    var currentIndex : CGFloat! 
    currentIndex = CGFloat((self.collectionView!.indexPathsForVisibleItems()[0] as! NSIndexPath).row) 
    if let currentVal = currentIndex{ 
     self.collectionView!.contentOffset = CGPointMake(currentIndex * self.collectionView!.frame.width, self.collectionView!.contentOffset.y); 
    } 
    }  
} 
+1

Questo funziona benissimo! 'willRotateToInterfaceOrientation' è deprecato in iOS 8 ma' viewWillTransitionToSize' funziona altrettanto bene per questo. – keegan3d

7

Swift: Raccolta delle cellule di vista che è n% dell'altezza dello schermo

mi serviva era una cella che era una certa percentuale di altezza delle viste e si ridimensionava con la rotazione del dispositivo.

Con l'aiuto dall'alto, ecco la soluzione risposta

override func viewDidLoad() { 
    super.viewDidLoad() 
    automaticallyAdjustsScrollViewInsets = false 
    // if inside nav controller set to true 
} 

override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { 
    collectionViewLayout.invalidateLayout() 
} 

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { 
    return CGSize(width: 100, height: collectionView.frame.height * 0.9) 
} 
Problemi correlati