2017-03-16 3 views
1

Ich habe einen UICollectionViewSubclass mit einem benutzerdefinierten UICOllectionViewLayoutWie Sie sich richtig itemSize von UICollectionViewLayout auf Orientierungsänderung Griff

Wie am besten finde ich die itemSize Veränderung Veränderung auf Orientierung umgehen?

class CollectSubclass: UICollectionView { 

    /// When orientation changes, then invalidate the layout 
    open override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { 
     super.traitCollectionDidChange(previousTraitCollection) 

     if ((traitCollection.verticalSizeClass != previousTraitCollection?.verticalSizeClass) || (traitCollection.horizontalSizeClass != previousTraitCollection?.horizontalSizeClass)) { 
      collectionViewLayout.invalidateLayout() 
     } 
    } 
} 

Nachdem das Layout auf Orientierungsänderung für ungültig erklärt wird, berechne ich die size.width der Zelle, auf die der width des UICollectionView.

Das funktioniert gut, der iPhone 7 Plus-Simulator, aber nicht auf den kleineren Simulatoren wie iPhone 7, 5, SE usw.

Es scheint, dass, sobald die invalidateLayout genannt wird, wird

die folgende Funktion ausgelöst
/// Lays out subviews. 
override open func layoutSubviews() { 
    super.layoutSubviews() 
} 

Diese Funktion wiederum ruft die prepare-Funktion auf der UICollectionViewLayout-Unterklasse auf, wo ich einen neuen Rahmen der Auflistung verwenden, um die Größe der Zelle zu berechnen.

Auf iPhone-7-Plus wird traitCollectionDidChange einmal ausgelöst. Und layoutSubviews wird einmal ausgelöst, was dazu führt, dass prepare einmal ausgelöst wird.

Bei den kleineren Simulatoren wird traitCollectionDidChange einmal ausgelöst, aber layoutSubviews wird zweimal ausgelöst.

Mit dem ersten Trigger von layoutSubviews ist die UICOlectionView-Rahmengröße fast, was es sein sollte. Und beim zweiten Trigger hat die UICOlectionView-Rahmengröße jetzt die richtige Größe, die es sein sollte.

Wenn zweimal mit zwei verschiedenen Rahmengrößen aufgerufen wird, muss ich das Layout zweimal vorbereiten (was sehr teuer ist).

Gibt es etwas, das ich vermisste, wenn ich UICOllectionViews und UICollectionViewLayouts unterklassifizierte? Jede Hilfe wird geschätzt.

Ich kann auch das Beispielprojekt zur Verfügung stellen, wenn benötigt

Antwort

1

Wenn in Ihrer Konfiguration, die Breite eines Ihrer UICollectionViewCells auf die Größe des UICollectionView und die Größe und Ausrichtung des Bildschirms allein basiert ((und keine anderen Faktoren), die folgende ist eine saubere Möglichkeit, die Größe einer Sammlungsansicht Zelle einzustellen:

1) Wenn die Ansicht zuerst lädt, vorberechnen, was die Größe einer Zelle im Hoch- und Querformat sein wird. Erstellen Sie außerdem eine Variable currCellDimensions, um die aktuellen Dimensionen einer Zelle zu speichern, und legen Sie ihren Anfangswert fest.

2) außer Kraft setzen, die Funktion viewWillTransitionToSize entlang dieser Linien:

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { 

    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) 
    setCurrentCollectionCellDimensions(size) // This code executes before the rotation begins, but "size" is the size that the main view is going to be after the rotation occurs. As of iOS 8, the size of an object swaps its width and its height when the UI changes its orientation. 
    } 

3) Implementieren setCurrentCollectionCellDimensions():

func setCurrentCollectionCellDimensions(newSize: CGSize) { 

    if (newSize.width < newSize.height) { 
     // set currCellDimensions to what it should be in portrait orientation 
    } else { 
     // set currCellDimension to what it should be in landscape orientation 
    } 

    if collectionView != nil { 

     collectionView.collectionViewLayout.invalidateLayout() // To trigger sizeForItemAtIndexPath to recalculate cell sizes 

    collectionView.reloadData() // To trigger cellForItemAtIndexPath to redraw the cells that are visible to the user. Without this call, the cell layout looks wrong on some iPhones. 
    } 
} 

4) Schließlich haben sizeForItemAtIndexPath() return currCellDimensions.

+0

Hallo, ich kann die Funktion 'viewWillTransitionToSize' nicht verwenden, da ich eine UICOllectionView-Unterklasse, keine UIViewCOntroller-Unterklasse erstelle. Ich habe keinen Zugriff auf den ViewController (außer nur als schwacher Delegat für die CollectionView) –

+0

Gibt es eine Möglichkeit, die 'viewWillTransitionToSize' zu ​​kennen, ohne einen View-Controller zu verwenden? –

+0

Nein, aber in welcher Ansicht Controller eine Instanz Ihrer Unterklasse 'UICollectionView' instanziiert, können Sie 'viewWillTransitionToSize()' implementieren. Dann rufen Sie in 'viewWillTransitionToSize()' anstelle des Aufrufs von 'setCurrentCollectionCellDimensions (size)' 'collectionView.setCurrentCollectionCellDimensions (size)' auf. Einige Ihrer Logik müssen vom View-Controller stammen und einige davon sind Teil Ihrer UICollectionView-Unterklasse. aber sie können miteinander kommunizieren. – ClayJ

Verwandte Themen