Ich verwende in meinem Projekt eine UICollectionView, in der mehrere Zellen unterschiedlicher Breite in einer Linie vorhanden sind. Laut: https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/CollectionViewPGforIOS/UsingtheFlowLayout/UsingtheFlowLayout.html
Es verteilt die Zellen mit gleicher Polsterung über die Linie. Dies geschieht wie erwartet, außer ich möchte sie linksbündig ausrichten und eine Auffüllbreite fest codieren.
Ich glaube, ich muss UICollectionViewFlowLayout in eine Unterklasse unterteilen, aber nachdem ich einige der Tutorials usw. online gelesen habe, verstehe ich einfach nicht, wie das funktioniert.
Antworten:
Die anderen Lösungen in diesem Thread funktionieren nicht richtig, wenn die Zeile nur aus 1 Element besteht oder zu kompliziert ist.
Anhand des Beispiels von Ryan habe ich den Code geändert, um eine neue Zeile zu erkennen, indem ich die Y-Position des neuen Elements überprüft habe. Sehr einfach und schnell in der Leistung.
Schnell:
Wenn Sie möchten, dass zusätzliche Ansichten ihre Größe beibehalten, fügen Sie oben im Abschluss des
forEach
Aufrufs Folgendes hinzu :Ziel c:
quelle
let attributes = super.layoutAttributesForElementsInRect(rect)?.map { $0.copy() as! UICollectionViewLayoutAttributes }
In den Antworten auf diese Frage sind viele großartige Ideen enthalten. Die meisten von ihnen haben jedoch einige Nachteile:
Die meisten Lösungen überschreiben nur die
layoutAttributesForElements(in rect: CGRect)
Funktion. Sie überschreiben nichtlayoutAttributesForItem(at indexPath: IndexPath)
. Dies ist ein Problem, da die Sammlungsansicht die letztere Funktion regelmäßig aufruft, um die Layoutattribute für einen bestimmten Indexpfad abzurufen. Wenn Sie von dieser Funktion nicht die richtigen Attribute zurückgeben, treten wahrscheinlich alle Arten von visuellen Fehlern auf, z. B. beim Einfügen und Löschen von Animationen von Zellen oder bei Verwendung von Zellen mit Selbstgröße durch Festlegen des Layouts der SammlungsansichtestimatedItemSize
. In den Apple-Dokumenten heißt es :Viele Lösungen machen auch Annahmen über den
rect
Parameter, der an dielayoutAttributesForElements(in rect: CGRect)
Funktion übergeben wird. Zum Beispiel basieren viele auf der Annahme, dass dasrect
immer am Anfang einer neuen Zeile beginnt, was nicht unbedingt der Fall ist.Also mit anderen Worten:
Die meisten der auf dieser Seite vorgeschlagenen Lösungen funktionieren für bestimmte Anwendungen, funktionieren jedoch nicht in jeder Situation wie erwartet.
AlignedCollectionViewFlowLayout
Um diese Probleme anzugehen, habe ich eine
UICollectionViewFlowLayout
Unterklasse erstellt, die einer ähnlichen Idee folgt, wie sie von Matt und Chris Wagner in ihren Antworten auf eine ähnliche Frage vorgeschlagen wurde. Es kann entweder die Zellen ausrichten⬅︎ links :
oder ➡︎ richtig :
und bietet zusätzlich Optionen zum vertikalen Ausrichten der Zellen in ihren jeweiligen Zeilen (falls sie in der Höhe variieren).
Sie können es einfach hier herunterladen:
https://github.com/mischa-hildebrand/AlignedCollectionViewFlowLayout
Die Verwendung ist unkompliziert und wird in der README-Datei erläutert. Sie erstellen im Grunde eine Instanz von
AlignedCollectionViewFlowLayout
, geben die gewünschte Ausrichtung an und weisen sie dercollectionViewLayout
Eigenschaft Ihrer Sammlungsansicht zu :(Es ist auch auf Cocoapods erhältlich .)
So funktioniert es (für linksbündige Zellen):
Das Konzept hier besteht darin, sich ausschließlich auf die
layoutAttributesForItem(at indexPath: IndexPath)
Funktion zu verlassen . In erhaltenlayoutAttributesForElements(in rect: CGRect)
wir einfach die Indexpfade aller Zellen innerhalb derrect
und rufen dann die erste Funktion für jeden Indexpfad auf, um die richtigen Frames abzurufen:(Die
copy()
Funktion erstellt einfach eine tiefe Kopie aller Layoutattribute im Array. Sie können den Quellcode für seine Implementierung untersuchen.)Jetzt müssen wir nur noch die
layoutAttributesForItem(at indexPath: IndexPath)
Funktion richtig implementieren . Die Superklasse fügtUICollectionViewFlowLayout
bereits die richtige Anzahl von Zellen in jede Zeile ein, sodass wir sie nur innerhalb ihrer jeweiligen Zeile nach links verschieben müssen. Die Schwierigkeit liegt in der Berechnung des Platzbedarfs, den wir benötigen, um jede Zelle nach links zu verschieben.Da wir einen festen Abstand zwischen den Zellen haben möchten, besteht die Kernidee darin, einfach anzunehmen, dass die vorherige Zelle (die Zelle links von der aktuell angelegten Zelle) bereits richtig positioniert ist. Dann müssen wir nur den Zellenabstand zum
maxX
Wert des Rahmens der vorherigen Zelle hinzufügen , und das ist derorigin.x
Wert für den Rahmen der aktuellen Zelle.Jetzt müssen wir nur noch wissen, wann wir den Anfang einer Zeile erreicht haben, damit wir keine Zelle neben einer Zelle in der vorherigen Zeile ausrichten. (Dies würde nicht nur zu einem falschen Layout führen, sondern auch extrem verzögert.) Wir benötigen also einen Rekursionsanker. Der Ansatz, mit dem ich diesen Rekursionsanker finde, ist der folgende:
Um herauszufinden, ob sich die Zelle am Index i in derselben Zeile befindet wie die Zelle mit dem Index i-1 ...
... Ich "zeichne" ein Rechteck um die aktuelle Zelle und strecke es über die Breite der gesamten Sammlungsansicht. Da die
UICollectionViewFlowLayout
Zentren alle Zellen vertikal zentrieren, muss sich jede Zelle in derselben Linie mit diesem Rechteck schneiden.Daher überprüfe ich einfach, ob sich die Zelle mit dem Index i-1 mit diesem Linienrechteck schneidet, das aus der Zelle mit dem Index i erstellt wurde .
Wenn es sich schneidet, ist die Zelle mit dem Index i nicht die Zelle ganz links in der Zeile.
→ Holen Sie sich den Frame der vorherigen Zelle (mit dem Index i - 1 ) und verschieben Sie die aktuelle Zelle daneben.
Wenn es sich nicht schneidet, ist die Zelle mit dem Index i die Zelle ganz links in der Zeile.
→ Bewegen Sie die Zelle an den linken Rand der Sammlungsansicht (ohne ihre vertikale Position zu ändern).
Ich werde die tatsächliche Implementierung der
layoutAttributesForItem(at indexPath: IndexPath)
Funktion hier nicht veröffentlichen, da ich denke, dass der wichtigste Teil darin besteht, die Idee zu verstehen , und Sie meine Implementierung immer im Quellcode überprüfen können . (Es ist etwas komplizierter als hier erklärt, da ich auch die.right
Ausrichtung und verschiedene vertikale Ausrichtungsoptionen zulasse . Es folgt jedoch der gleichen Idee.)Wow, ich denke, dies ist die längste Antwort, die ich jemals auf Stackoverflow geschrieben habe. Ich hoffe das hilft. 😉
quelle
Mit Swift 4.1 und iOS 11 können Sie je nach Bedarf eine der beiden folgenden vollständigen Implementierungen auswählen , um Ihr Problem zu beheben.
# 1. Autoresizing links ausrichten
UICollectionViewCell
sDie folgende Implementierung zeigt, wie
UICollectionViewLayout
'slayoutAttributesForElements(in:)
,UICollectionViewFlowLayout
' sestimatedItemSize
undUILabel
's verwendetpreferredMaxLayoutWidth
werden, um Autoresizing-Zellen in aUICollectionView
: links auszurichten.CollectionViewController.swift
FlowLayout.swift
CollectionViewCell.swift
Erwartetes Ergebnis:
# 2. Links
UICollectionViewCell
mit fester Größe ausrichtenDie folgende Implementierung zeigt, wie Sie
UICollectionViewLayout
'slayoutAttributesForElements(in:)
undUICollectionViewFlowLayout
' sitemSize
verwenden, um Zellen mit vordefinierter Größe in a links auszurichtenUICollectionView
:CollectionViewController.swift
FlowLayout.swift
CollectionViewCell.swift
Erwartetes Ergebnis:
quelle
10
eine beliebige Zahl verwendet?Die einfache Lösung im Jahr 2019
Dies ist eine dieser deprimierenden Fragen, bei denen sich die Dinge im Laufe der Jahre stark verändert haben. Es ist jetzt einfach.
Grundsätzlich machst du einfach Folgendes:
Jetzt brauchen Sie nur noch den Boilerplate-Code:
Kopieren Sie das einfach und fügen Sie es in a ein
UICollectionViewFlowLayout
- fertig.Voll funktionsfähige Lösung zum Kopieren und Einfügen:
Das ist das Ganze:
Und schlussendlich...
Bedanken Sie sich bei @AlexShubin oben, der dies zuerst geklärt hat!
quelle
Die Frage ist schon eine Weile offen, aber es gibt keine Antwort und es ist eine gute Frage. Die Antwort besteht darin, eine Methode in der UICollectionViewFlowLayout-Unterklasse zu überschreiben:
Wie von Apple empfohlen, erhalten Sie die Layoutattribute von super und durchlaufen sie. Wenn es das erste in der Zeile ist (definiert durch seinen Ursprung.x am linken Rand), lassen Sie es in Ruhe und setzen das x auf Null zurück. Dann addieren Sie für die erste Zelle und jede Zelle die Breite dieser Zelle plus einen Rand. Dies wird an das nächste Element in der Schleife übergeben. Wenn es nicht das erste Element ist, setzen Sie origin.x auf den laufenden berechneten Rand und fügen dem Array neue Elemente hinzu.
quelle
attribute.center.x == self.collectionView?.bounds.midX
leftMargin
mit derif (attributes.frame.origin.x == self.sectionInset.left) {
Prüfung zurück. Dies setzt voraus, dass das Standardlayout die Zelle der neuen Zeile so ausgerichtet hat, dass sie mit der Zelle bündig istsectionInset.left
. Ist dies nicht der Fall, würde sich das von Ihnen beschriebene Verhalten ergeben. Ich würde einen Haltepunkt in die Schleife einfügen und beide Seiten kurz vor dem Vergleich auf die Zelle der zweiten Zeile prüfen. Viel Glück.Ich hatte das gleiche Problem: Probieren Sie das Cocoapod UICollectionViewLeftAlignedLayout aus . Fügen Sie es einfach in Ihr Projekt ein und initialisieren Sie es wie folgt:
quelle
Aufbauend auf der Antwort von Michael Sand habe ich eine
UICollectionViewFlowLayout
Bibliothek mit Unterklassen erstellt , die links, rechts oder vollständig (im Grunde die Standardeinstellung) horizontal ausgerichtet ist. Außerdem können Sie den absoluten Abstand zwischen den einzelnen Zellen festlegen. Ich habe vor, auch eine horizontale und eine vertikale Ausrichtung hinzuzufügen.https://github.com/eroth/ERJustifiedFlowLayout
quelle
Hier ist die ursprüngliche Antwort in Swift. Meistens funktioniert es immer noch großartig.
Ausnahme: Autosizing-Zellen
Es gibt leider eine große Ausnahme. Wenn Sie
UICollectionViewFlowLayout
's verwendenestimatedItemSize
. InternUICollectionViewFlowLayout
ändert sich etwas. Ich habe es nicht vollständig aufgespürt, aber es ist klar, dass es andere Methoden aufruft,layoutAttributesForElementsInRect
während die Zellen selbst dimensioniert werden. Aus meinem Versuch und Irrtum habe ich herausgefunden, dass eslayoutAttributesForItemAtIndexPath
bei der automatischen Größenanpassung häufiger darum geht, jede Zelle einzeln aufzurufen. Dieses UpdateLeftAlignedFlowLayout
funktioniert hervorragend mitestimatedItemSize
. Es funktioniert auch mit Zellen mit statischer Größe. Die zusätzlichen Layoutaufrufe führen jedoch dazu, dass ich die ursprüngliche Antwort immer dann verwende, wenn ich keine Zellen mit automatischer Größe benötige.quelle
In kurzer Zeit. Laut Michaels Antwort
quelle
Aufgrund aller Antworten ändere ich mich ein wenig und es funktioniert gut für mich
quelle
Wenn jemand von Ihnen Probleme hat - einige der Zellen rechts in der Sammlungsansicht überschreiten die Grenzen der Sammlungsansicht . Dann benutzen Sie bitte diese -
Verwenden Sie INT anstelle des Vergleichs der CGFloat- Werte.
quelle
Basierend auf den Antworten hier, aber behobenen Abstürzen und Ausrichtungsproblemen, wenn Ihre Sammlungsansicht auch Kopf- oder Fußzeilen enthält. Nur linke Zellen ausrichten:
quelle
Danke für die Antwort von Michael Sand . Ich habe es in eine Lösung aus mehreren Zeilen (dieselbe Ausrichtung oben y jeder Zeile) geändert, bei der es sich um die linke Ausrichtung handelt, sogar um den Abstand zu jedem Element.
quelle
Hier ist meine Reise, um den besten Code zu finden, der mit Swift 5 funktioniert. Ich habe einige Antworten aus diesem Thread und einigen anderen Threads zusammengeführt, um Warnungen und Probleme zu lösen, mit denen ich konfrontiert war. Ich hatte eine Warnung und ein abnormales Verhalten beim Scrollen durch meine Sammlungsansicht. Die Konsole druckt Folgendes:
Ein weiteres Problem, mit dem ich konfrontiert war, ist, dass einige lange Zellen auf der rechten Seite des Bildschirms abgeschnitten werden. Außerdem habe ich die Abschnittseinfügungen und das MinimumInteritemSpacing in den Delegatfunktionen festgelegt, was dazu führte, dass Werte nicht in der benutzerdefinierten Klasse wiedergegeben wurden. Das Problem wurde behoben, indem diese Attribute auf eine Instanz des Layouts festgelegt wurden, bevor sie auf meine Sammlungsansicht angewendet wurden.
So habe ich das Layout für meine Sammlungsansicht verwendet:
Hier ist die Flow-Layout-Klasse
quelle
Das Problem mit UICollectionView besteht darin, dass versucht wird, die Zellen automatisch in den verfügbaren Bereich einzupassen. Ich habe dies getan, indem ich zuerst die Anzahl der Zeilen und Spalten und dann die Zellengröße für diese Zeile und Spalte definiert habe
1) So definieren Sie Abschnitte (Zeilen) meiner UICollectionView:
2) Definieren der Anzahl der Elemente in einem Abschnitt. Sie können für jeden Abschnitt eine andere Anzahl von Elementen definieren. Sie können die Abschnittsnummer mit dem Parameter 'section' abrufen.
3) Definieren der Zellengröße für jeden Abschnitt und jede Zeile separat. Sie können die Abschnittsnummer und die Zeilennummer mit dem Parameter 'indexPath' abrufen, dh
[indexPath section]
für die Abschnittsnummer und die[indexPath row]
Zeilennummer.4) Anschließend können Sie Ihre Zellen in Zeilen und Abschnitten anzeigen, indem Sie:
HINWEIS: In UICollectionView
quelle
Die Antwort von Mike Sand ist gut, aber ich hatte einige Probleme mit diesem Code (wie lange Zellen herausgeschnitten). Und neuer Code:
quelle
Die Antwort
minimumInteritemSpacing
von Angel García Olloqui auf den Respekt der Delegierten wurde bearbeitetcollectionView(_:layout:minimumInteritemSpacingForSectionAt:)
, wenn sie umgesetzt wird.quelle
Der obige Code funktioniert für mich. Ich möchte den jeweiligen Swift 3.0-Code teilen.
quelle