2016-04-27 6 views
3

Ich habe ein Dataset, das in mehrere Abschnitte unterteilt ist, jedoch möchte ich dies in einer CollectionView ohne Unterbrechungen zwischen den Abschnitten anzeigen. Hier ist ein Beispiel dafür, was ich erreichen möchte:UICollectionView entfernen Abschnitt bricht mit UICollectionViewFlowLayout

Instead of: 
0-0 0-1 0-2 
0-3 
1-0 1-1 
2-0 
3-0 

I want: 
0-0 0-1 0-2 
0-3 1-0 1-1 
2-0 3-0 

Mir ist klar, die Lösung wahrscheinlich liegt mit einer benutzerdefinierten UICollectionViewLayout Unterklasse, aber ich bin mir nicht sicher, wie so etwas zu erreichen.

Dank

+0

Mit nur einem Abschnitt wird das gewünschte Ergebnis erzielt. Gibt es einen Grund, warum Sie mehrere Abschnitte verwenden müssen? – bsmith11

+0

Ich verwende einen NSFetchedResultsController mit einem definierten sectionNameKeyPath, der die resultierenden Ergebnisse in diese Abschnitte aufteilt. Dieser Controller und die zwischengespeicherten Ergebnisse werden von dieser collectionView und einer anderen tableView gemeinsam verwendet, die die Abschnittsumbrüche anzeigt. Daher muss sectionNameKeyPath festgelegt werden. Ich weiß, dass ich ein paar funky NSIndexPath-Switching durchführen kann, damit es in einem Abschnitt für das CollectionView funktioniert, aber ich denke, dass die sauberste Lösung ist, das Flow-Layout stattdessen anzupassen. –

+0

Ich glaube nicht, dass es einen sauberen Weg gibt, um das zu erreichen, was Sie wollen, ohne 'UICollectionViewLayout' abzuleiten. Was ist, wenn Sie zwei separate 'NSFetchedResultsController's verwendet haben? – bsmith11

Antwort

0

Sie sind richtig, dass Sie UICollectionViewLayout Unterklasse benötigen. Das Wesentliche vor dem Start zu verstehen ist, dass Sie mindestens Position und Größe für jede Zelle in der Sammlungsansicht berechnen müssen. UICollectionViewLayout ist nur eine strukturierte Methode zur Bereitstellung dieser Informationen. Sie bekommen die Struktur, aber Sie müssen alles andere selbst bereitstellen.

Es gibt 4 Methoden, die Sie außer Kraft setzen müssen:

  • vorbereiten
  • invalidateLayout
  • layoutAttributesForItemAtIndexPath
  • layoutAttributesForElementsInRect

Ein Trick ist, die Layout-Attribute in einer Lookup-Tabelle cachen (Wörterbuch):

var cachedItemAttributes = [IndexPath: UICollectionViewLayoutAttributes]() 

In vorbereiten, berechnen Sie das Layout für jede indexPath in Ihrer Kollektion Attribute:

override func prepare() { 
    super.prepare() 
    calculateAttributes() 
} 

In invalidateLayout Sie die im Cache gespeicherten Layout Attribute zurückgesetzt und neu berechnen sie:

override func invalidateLayout() { 
    super.invalidateLayout() 
    cachedItemAttributes = [:] 
    calculateAttributes() 
} 

In layoutAttributesForItemAtIndexPath verwenden Sie die Suche Tabelle das richtige Layout zurückzukehren Attribute:

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 
    return cachedItemAttributes[indexPath] 
} 

In layoutAttributesForElementsInRect Sie Ihre Lookup-Tabelle für die Elemente innerhalb des angegebenen rect filtern:

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 
    return cachedItemAttributes.filter { rect.intersects($0.value.frame) }.map { $0.value } 
} 

Das letzte Stück des Puzzles ist die eigentliche Berechnung von die Layout-Attribute. Hier werde ich nur Pseudo-Code zur Verfügung stellen:

func calculateAttributes() { 
    // For each indexpath (you can get this from the collectionView property using numberOfSections and numberOfItems:inSection) 
    // calculate the frame, i.e the origin point and size of each cell in your collectionView and set it with UICollectionViewLayoutAttributes.frame 
    // There are many other properties on UICollectionViewLayoutAttributes that you can tweak for your layout, but frame is a good starting point from which you can start experimenting. 
    // Add the layout attributes to the lookup table 
    // end loop 
} 

Um Ihre Frage zu beantworten, hier ist Pseudo-Code die Position jeder Zelle zu berechnen:

// If width of cell + current width of row + spacing, insets and margins exceeds the available width 
// move to next row. 
// else 
// cell origin.x = current width of row + interitem spacing 
// cell origin.y = number of rows * (row height + spacing) 
// endif 

Wenn Sie Ihr eigenes Layout konfigurierbar sein, verwenden Sie entweder UICollectionViewDelegateFlowLayout, wenn die verfügbaren Signaturen ausreichend sind, oder definieren Sie Ihre eigenen, die von UICollectionViewDelegateFlowLayout oder UICollectionViewDelegate erben.Da Ihr Protokoll von UICollectionViewDelegateFlowLayout erbt, das wiederum von UICollectionViewDelegate erbt, können Sie es direkt als den CollectView-Delegaten in Ihrem Viewcontroller festlegen. In Ihrem benutzerdefinierten Auflistungsansichtslayout müssen Sie den Delegaten nur von UICollectionViewDelegate in Ihr benutzerdefiniertes Protokoll umwandeln, um ihn zu verwenden. Denken Sie daran, Fälle zu behandeln, in denen das Casting fehlschlägt oder die Protokollmethoden nicht vom Delegaten implementiert werden.