16

2015/08/18 16: 07: 51,523 Esempio [16070: 269.647] il comportamento del UICollectionViewFlowLayout non è definito perché: 2015-08-18 16: 07: 51.523
Esempio [16070: 269647] la larghezza dell'articolo deve essere inferiore a la larghezza di UICollectionView meno i valori di sezione rimasti e valori corretti, meno il contenuto inserisce i valori sinistro e destro .
2015-08-18 16: 07: 51.524 Esempio [16070: 269647] L'istanza di UICollectionViewFlowLayout è, ed è collegata a; animazioni = { position =; bounds.origin =; bounds.size =; }; layer =; contentOffset: {0, 0}; contentSize: {1024, 770}> layout vista collezione:. 2015-08-18 16: 07: 51.524 Esempio [16070: 269647] Crea un breakpoint simbolico in UICollectionViewFlowLayoutBreakForInvalidSizes per catturare nel debugger.il comportamento del UICollectionViewFlowLayout non è definito, poiché la larghezza della cella è superiore alla larghezza CollectionView

Questo è quello che mi capita, quello che faccio è

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { 
     return CGSizeMake(self.collectionView!.frame.size.width - 20, 66) 
    } 

quando ho ruotare da orizzontale a verticale, la console mostra questo messaggio di errore solo in iOS 9, qualcuno sa che cosa questo accade e se c'è una soluzione per questo?

Screenshot

+0

Il problema è stato risolto? –

+0

no, non risolto –

risposta

0

ho avuto un problema simile.

Nel mio caso, avevo una vista raccolta e quando si toccava una delle celle, si apriva un popover con UITextField per modificare l'elemento. Dopo che il popover è scomparso, lo self.collectionView.contentInset.bottom è stato impostato su 55 (originariamente 0).

Per risolvere il problema, una volta scomparsa la visualizzazione popover, sto impostando manualmente contentInset su UIEdgeInsetsZero.

contextual prediction bar

Il problema originale sembra essere correlata alla barra previsione contestuale che presenta sulla parte superiore della tastiera. Quando la tastiera è nascosta, la barra scompare, ma il valore contentInset.bottom non viene ripristinato al valore originale.

Poiché il problema sembra essere correlato alla larghezza e non all'altezza della cella, verificare se uno qualsiasi dei valori contentInset o layout.sectionInset è uguale a quello impostato dall'utente.

7

Succede perché la larghezza della cella della vista di raccolta è maggiore della larghezza della vista di raccolta dopo la rotazione. Supponiamo di avere uno schermo 1024x768 e la vista della collezione riempie lo schermo. Quando il dispositivo è orizzontale, la larghezza della cella sarà self.collectionView .frame.size.width - 20 = 1004 ed è maggiore della larghezza della vista dell'insieme in portrait = 768. Il debugger dice che "la larghezza dell'elemento deve essere inferiore alla larghezza di UICollectionView meno la sezione inserisce i valori left e right, meno il contenuto inserisce i valori sinistro e destro ".

+0

Giusto ... quindi come lo risolvono ... – Magoo

+0

@Magoo È possibile risolvere il problema modificando i valori del layout del flusso di visualizzazione della raccolta per la dimensione dell'articolo. Il delegato deve prendere in considerazione la rotazione. Come dice il debugger, la larghezza dell'elemento deve essere inferiore alla larghezza di UICollectionView meno la sezione inserisce i valori left e right, meno il contenuto inserisce i valori left e right. – mohammadrhemmati

4

Sto utilizzando una sottoclasse di UICollectionViewFlowLayout e utilizzo della sua proprietà itemSize per specificare la dimensione della cella (anziché il metodo delegato collectionView:sizeForItemAtIndexPath:). Ogni volta che ruoto lo schermo su una larghezza inferiore (ad esempio paesaggio -> ritratto) ottengo questo enorme avvertimento in questione.

Sono stato in grado di risolverlo facendo 2 passaggi.

Fase 1: In UICollectionViewFlowLayout funzione di sottoclasse prepareLayout(), spostare super.prepareLayout() a dopo in cui è impostato self.itemSize. Penso che questo faccia sì che la super classe utilizzi il valore corretto itemSize.

import UIKit 

extension UICollectionViewFlowLayout { 

    var collectionViewWidthWithoutInsets: CGFloat { 
    get { 
     guard let collectionView = self.collectionView else { return 0 } 
     let collectionViewSize = collectionView.bounds.size 
     let widthWithoutInsets = collectionViewSize.width 
     - self.sectionInset.left - self.sectionInset.right 
     - collectionView.contentInset.left - collectionView.contentInset.right 
     return widthWithoutInsets 
    } 
    } 

} 

class StickyHeaderCollectionViewLayout: UICollectionViewFlowLayout { 

    // MARK: - Variables 
    let cellAspectRatio: CGFloat = 3/1 

    // MARK: - Layout 
    override func prepareLayout() { 
    self.scrollDirection = .Vertical 
    self.minimumInteritemSpacing = 1 
    self.minimumLineSpacing = 1 
    self.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: self.minimumLineSpacing, right: 0) 
    let collectionViewWidth = self.collectionView?.bounds.size.width ?? 0 
    self.headerReferenceSize = CGSize(width: collectionViewWidth, height: 40) 

    // cell size 
    let itemWidth = collectionViewWidthWithoutInsets 
    self.itemSize = CGSize(width: itemWidth, height: itemWidth/cellAspectRatio) 

    // Note: call super last if we set itemSize 
    super.prepareLayout() 
    } 

    // ... 

} 

noti che la suddetta variazione in qualche modo rendere il cambio formato layout quando schermo ruota smette di funzionare. Questo è dove il punto 2 è disponibile in

Fase 2:. Mettere questo nel controller vista che contiene la vista di raccolta.

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

Ora l'allarme è andato :)

+1

guarda male questa soluzione, la risposta è arrivata molto più tardi rispetto a quando sono uscito dal progetto :( –

12

Questo accade quando la visualizzazione collezione ridimensiona a qualcosa di meno ampia (passare dal paesaggio al modo verticale, per esempio), e la cellula diventa troppo grande per adattarsi.

Perché la cella diventa troppo grande, poiché il layout del flusso di visualizzazione della raccolta deve essere richiamato e restituire una dimensione adeguata?

CollectionView (CollectionView: UICollectionView, il layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath)

aggiornamento per includere Swift 4

esclusione @objc func CollectionView (_ CollectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {...}

Questo perché questa funzione è non chiamata, o almeno non immediatamente.

Ciò che accade è che la sottoclasse del layout del flusso di visualizzazione della raccolta non sostituisce la funzione shouldInvalidateLayoutForBoundsChange, che per impostazione predefinita è returns false.

Quando questo metodo restituisce false, la vista di raccolta prima tenta di andare con la dimensione corrente della cella, rileva un problema (che registra l'avviso) e quindi chiama il layout del flusso per ridimensionare la cella.

Ciò significa 2 cose:

1 - l'avviso di per sé non è dannoso

2 - è possibile sbarazzarsi di esso, semplicemente ignorando la funzione shouldInvalidateLayoutForBoundsChange per restituire true. In tal caso, il layout del flusso verrà sempre chiamato quando i limiti della vista di raccolta cambiano.

+0

Ho provato tutti i possibili suggerimenti su internet e questa è la risposta giusta !!! Grazie mille per la tua spiegazione dettagliata e soluzione semplice! Se potessi, revocherò questa risposta per 10 volte. – ElectroBuddha

+0

Grazie, questo ha funzionato per me. UPDATE per swift 4: cambia "sizeForItemAtIndexPath" su "sizeForItem" altrimenti NON funzionerà e NON mostrerà alcun errore. –

3

È possibile eseguire il check in del debugger se collectionView.contentOffset viene modificato in negativo nel mio caso cambia da (0,0) a (0,-40).È possibile risolvere questo problema utilizzando questo metodo

if ([self respondsToSelector:@selector(setAutomaticallyAdjustsScrollViewInsets:)]) { 
    self.automaticallyAdjustsScrollViewInsets = NO; 
} 
2

Dopo aver fatto alcuni esperimenti, questo sembra anche essere legato al modo di impostare il layout vostra CollectionView.

Il file tl; dr è: Usa AutoLayout, non autoresizingMask.

Così, per il nucleo del problema delle migliori soluzioni che ho trovato per gestire il cambiamento dell'orientamento utilizzare il codice seguente, che tutto ha un senso:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 
    super.viewWillTransition(to: size, with: coordinator) 

    coordinator.animate(alongsideTransition: { (context) in 
     self.collectionView.collectionViewLayout.invalidateLayout() 
    }, completion: nil) 
} 

Tuttavia, ci sono ancora situazioni in cui è possibile ricevi l'avvertenza sulla dimensione dell'articolo. Per me è se sono in un paesaggio in una scheda, passare a un'altra scheda, ruotare in verticale, quindi tornare alla scheda precedente. Ho provato a invalidare il layout in WillAppear, willLayout, tutti i soliti sospetti, ma senza fortuna. Infatti, anche se chiami invalidateLayoutprima delsuper.willAppear() ricevi comunque l'avviso.

E in definitiva, questo problema è legato alla dimensione dei limiti di raccolta dei limiti di visualizzazione prima che venga richiesto al delegato itemSize.

Quindi con questo in mente ho provato a usare AutoLayout invece di collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight], e con questo problema risolto! (Io uso SnapKit per fare AutoLayout in modo da non strapparmi i capelli costantemente). È inoltre sufficiente invalidateLayout in viewWillTransition (senza lo coordinator.animate, così come nel tuo esempio), e anche invalidateLayout nella parte inferiore di viewWillAppear(:). Che sembra per coprire tutte le situazioni.

Non so se si sta usando l'autoresizing o no - sarebbe interessante sapere se la mia teoria/soluzione funziona per tutti.

1

Ho avuto lo stesso problema. Ho risolto questo problema cancellando la mia vista dell'insieme dei suoi vincoli e reimpostandoli in Storyboard.

-1

Questo è quello che vi serve:

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 
    //Get frame width 
    let width = self.view.frame.width 
    //I want a width of 418 and height of 274 (Aspect ratio 209:137) with a margin of 24 on each side of the cell (See insetForSectionAt 24 + 24 = 48). So, check if a have that much screen real estate. 
    if width > (418 + 48) { 
     //If I do return the size I want 
     return CGSize(width: 418, height: 274) 
    }else{ 
     //Get new width. Frame width minus the margins I want to maintain 
     let newWidth = (width - 48) 
     //If not calculate the new height that maintains the aspect ratio I want. NewHeight = (originalHeight/originalWidth) * newWidth 
     let height = (274/418) * newWidth 
     //Return the new size that is Aspect ratio 209:137 
     return CGSize(width: newWidth, height: height) 
    } 
} 

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets { 
    return UIEdgeInsets(top: 24, left: 24, bottom: 24, right: 24) 
} 

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 
    return 33 
} 

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 
    return 33 
} 
1

ho risolvere questo problema utilizzando safeAreaLayoutGuide.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { 

    return CGSize(width: (view.safeAreaLayoutGuide.layoutFrame.width), height: 80); 
} 

ed è inoltre necessario sovrascrivere questa funzione per supportare correttamente la modalità verticale e orizzontale.

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 
    collectionView?.collectionViewLayout.invalidateLayout(); 
} 
Problemi correlati