Ich versuche, die Selbstgröße UICollectionViewCells
mit Auto Layout zu erreichen, aber ich kann die Zellen scheinbar nicht dazu bringen, sich an den Inhalt anzupassen. Ich habe Probleme zu verstehen, wie die Größe der Zelle anhand des Inhalts der Inhaltsansicht der Zelle aktualisiert wird.
Hier ist das Setup, das ich versucht habe:
- Benutzerdefiniert
UICollectionViewCell
mit einemUITextView
in seiner Inhaltsansicht. - Das Scrollen nach
UITextView
ist deaktiviert. - Die horizontale Einschränkung von contentView lautet: "H: | [_textView (320)]", dh die
UITextView
wird links von der Zelle mit einer expliziten Breite von 320 angeheftet . - Die vertikale Einschränkung von contentView lautet: "V: | -0 - [_ textView]", dh die
UITextView
am oberen Rand der Zelle angeheftete . - Für
UITextView
hat eine Höhenbeschränkung auf eine Konstante festgelegt, derenUITextView
Berichte in den Text passen.
So sieht es aus, wenn der Zellenhintergrund auf Rot und der UITextView
Hintergrund auf Blau eingestellt ist:
Ich habe das Projekt, mit dem ich gespielt habe, hier auf GitHub gestellt .
Antworten:
Aktualisiert für Swift 5
preferredLayoutAttributesFittingAttributes
umbenannt inpreferredLayoutAttributesFitting
und verwenden Sie die automatische GrößenanpassungAktualisiert für Swift 4
systemLayoutSizeFittingSize
umbenannt insystemLayoutSizeFitting
Aktualisiert für iOS 9
Nachdem ich gesehen hatte, dass meine GitHub-Lösung unter iOS 9 kaputt ging, hatte ich endlich die Zeit, das Problem vollständig zu untersuchen. Ich habe das Repo jetzt aktualisiert und einige Beispiele für verschiedene Konfigurationen für Zellen mit Selbstgröße hinzugefügt. Mein Fazit ist, dass Zellen mit Selbstgröße theoretisch großartig, in der Praxis jedoch chaotisch sind. Ein Wort der Vorsicht, wenn Sie mit Zellen mit Selbstgröße fortfahren.
TL; DR
Schauen Sie sich mein GitHub-Projekt an
Zellen mit Selbstgröße werden nur mit Ablauflayout unterstützt. Stellen Sie daher sicher, dass Sie diese verwenden.
Es gibt zwei Dinge, die Sie einrichten müssen, damit Zellen mit Selbstgröße funktionieren.
1. Stellen Sie
estimatedItemSize
aufUICollectionViewFlowLayout
Das Flow-Layout wird von Natur aus dynamisch, sobald Sie die
estimatedItemSize
Eigenschaft festlegen .2. Fügen Sie Unterstützung für die Größenbestimmung in Ihrer Zellunterklasse hinzu
Dies kommt in 2 Geschmacksrichtungen; Auto-Layout oder benutzerdefinierte Überschreibung von
preferredLayoutAttributesFittingAttributes
.Erstellen und konfigurieren Sie Zellen mit Auto Layout
Ich werde nicht näher darauf eingehen, da es einen brillanten SO-Beitrag zum Konfigurieren von Einschränkungen für eine Zelle gibt. Seien Sie nur vorsichtig, dass Xcode 6 mit iOS 7 eine Reihe von Problemen gelöst hat. Wenn Sie also iOS 7 unterstützen, müssen Sie beispielsweise sicherstellen, dass die Autoresizing-Maske in der Inhaltsansicht der Zelle festgelegt ist und dass die Grenzen der Inhaltsansicht als die Grenzen der Zelle festgelegt werden, wenn Die Zelle wird geladen (dh
awakeFromNib
).Was Sie beachten müssen, ist, dass Ihre Zelle stärker eingeschränkt werden muss als eine Zelle mit Tabellenansicht. Wenn Sie beispielsweise möchten, dass Ihre Breite dynamisch ist, benötigt Ihre Zelle eine Höhenbeschränkung. Wenn Sie möchten, dass die Höhe dynamisch ist, benötigen Sie ebenfalls eine Breitenbeschränkung für Ihre Zelle.
Implementieren Sie
preferredLayoutAttributesFittingAttributes
in Ihrer benutzerdefinierten ZelleWenn diese Funktion aufgerufen wird, wurde Ihre Ansicht bereits mit Inhalten konfiguriert (dh
cellForItem
aufgerufen). Unter der Annahme, dass Ihre Einschränkungen angemessen festgelegt wurden, könnten Sie eine Implementierung wie diese haben:HINWEIS Unter iOS 9 hat sich das Verhalten etwas geändert, was zu Abstürzen Ihrer Implementierung führen kann, wenn Sie nicht vorsichtig sind (weitere Informationen finden Sie hier ). Bei der Implementierung müssen
preferredLayoutAttributesFittingAttributes
Sie sicherstellen, dass Sie den Rahmen Ihrer Layoutattribute nur einmal ändern. Wenn Sie dies nicht tun, ruft das Layout Ihre Implementierung auf unbestimmte Zeit auf und stürzt schließlich ab. Eine Lösung besteht darin, die berechnete Größe in Ihrer Zelle zwischenzuspeichern und diese jedes Mal ungültig zu machen, wenn Sie die Zelle wiederverwenden oder ihren Inhalt ändern, wie ich es mit derisHeightCalculated
Eigenschaft getan habe .Erleben Sie Ihr Layout
Zu diesem Zeitpunkt sollten in Ihrer collectionView "funktionierende" dynamische Zellen vorhanden sein. Ich habe die Out-of-the-Box-Lösung während meiner Tests noch nicht als ausreichend befunden. Wenn Sie dies getan haben, können Sie dies gerne kommentieren. Es fühlt sich immer noch so an, als würde
UITableView
der Kampf um die dynamische Dimensionierung IMHO gewonnen.Vorsichtsmaßnahmen
Beachten Sie sehr, dass bei Verwendung von Prototypzellen zur Berechnung der geschätzten Artikelgröße dies unterbrochen wird, wenn Ihre XIB Größenklassen verwendet . Der Grund dafür ist, dass beim Laden Ihrer Zelle von einem XIB die Größenklasse mit konfiguriert wird
Undefined
. Dies wird nur unter iOS 8 und höher unterbrochen, da unter iOS 7 die Größenklasse basierend auf dem Gerät geladen wird (iPad = Regular-Any, iPhone = Compact-Any). Sie können entweder die geschätzte Größe festlegen, ohne die XIB zu laden, oder Sie können die Zelle aus der XIB laden, sie zur collectionView hinzufügen (dies legt die traitCollection fest), das Layout ausführen und sie dann aus der Übersicht entfernen. Alternativ können Sie auch festlegen, dass Ihre Zelle dentraitCollection
Getter überschreibt und die entsprechenden Merkmale zurückgibt. Es liegt an dir.Lassen Sie mich wissen, wenn ich etwas verpasst habe, hoffe ich habe geholfen und viel Glück beim Codieren
quelle
estimatedItemSize
führt zu Abstürzen - es scheint einen großen Fehler zu geben, wie das automatische Layout versucht, die UICollectionViewCell zu verarbeiten.In iOS10 gibt es eine neue Konstante namens
UICollectionViewFlowLayout.automaticSize
(früherUICollectionViewFlowLayoutAutomaticSize
), also stattdessen:Sie können dies verwenden:
Es bietet eine bessere Leistung, insbesondere wenn die Zellen in Ihrer Sammlungsansicht eine konstante Breite haben
Zugriff auf das Flow-Layout:
Swift 5 Aktualisiert:
quelle
collectionViewLayout
und überprüfen, ob es vom Typ istUICollectionViewFlowLayout
Ein paar wichtige Änderungen an Daniel Galaskos Antwort haben alle meine Probleme behoben. Leider habe ich (noch) nicht genug Ruf, um direkt zu kommentieren.
Fügen Sie in Schritt 1 bei Verwendung des automatischen Layouts einfach eine übergeordnete UIView zur Zelle hinzu. ALLES in der Zelle muss eine Unteransicht des übergeordneten Elements sein. Das hat alle meine Probleme beantwortet. Während Xcode dies für UITableViewCells automatisch hinzufügt, ist dies für UICollectionViewCells nicht der Fall (sollte es aber sein). Laut den Dokumenten :
Überspringen Sie dann Schritt 3 vollständig. Es wird nicht benötigt.
quelle
contentView
, beschwert sich Xcode über Konflikte mit vorhandenen Eigenschaften. Es wurde versucht, Unteransichten hinzuzufügenself.contentView
und Einschränkungen festzulegen , dann stürzt die App ab.In iOS 10+ ist dies ein sehr einfacher 2-Schritt-Prozess.
Stellen Sie sicher, dass alle Ihre Zelleninhalte in einem einzelnen UIView (oder in einem Nachkommen von UIView wie UIStackView, das das automatische Layout erheblich vereinfacht) platziert sind. Genau wie bei der dynamischen Größenänderung von UITableViewCells müssen für die gesamte Ansichtshierarchie Einschränkungen konfiguriert werden, vom äußersten Container bis zur innersten Ansicht. Dies schließt Einschränkungen zwischen der UICollectionViewCell und der unmittelbaren untergeordneten Ansicht ein
Weisen Sie das Flowlayout Ihres UICollectionView an, die Größe automatisch anzupassen
quelle
UICollectionViewFlowLayout.automaticSize
in umbenannt wurdeUICollectionViewFlowLayoutAutomaticSize
.Fügen Sie flowLayout in viewDidLoad () hinzu
Legen Sie außerdem eine UIView als mainContainer für Ihre Zelle fest und fügen Sie alle erforderlichen Ansichten hinzu.
Weitere Informationen finden Sie in diesem fantastischen, umwerfenden Tutorial: UICollectionView mit Autosize-Zelle mithilfe von Autolayout in iOS 9 und 10
quelle
EDIT 19.11.19: Verwenden Sie für iOS 13 einfach UICollectionViewCompositionalLayout mit geschätzten Höhen. Verschwenden Sie keine Zeit mit dieser kaputten API.
Nachdem ich einige Zeit damit zu kämpfen hatte, stellte ich fest, dass die Größenänderung für UITextViews nicht funktioniert, wenn Sie das Scrollen nicht deaktivieren:
quelle
contentView-Ankerrätsel:
In einem bizarren Fall dies
würde nicht funktionieren. Der contentView wurden vier explizite Anker hinzugefügt, und es hat funktioniert.
und wie immer
im
YourLayout: UICollectionViewFlowLayout
Wer weiß? Könnte jemandem helfen.
Anerkennung
https://www.vadimbulavin.com/collection-view-cells-self-sizing/
stolperte dort über das Trinkgeld - habe es in all den 1000er-Artikeln dazu nirgendwo anders gesehen.
quelle
Ich habe eine dynamische Zellenhöhe der Sammlungsansicht erstellt. Hier ist Git Hub Repo .
Finden Sie heraus, warum PreferredLayoutAttributesFittingAttributes mehrmals aufgerufen wird. Eigentlich wird es mindestens 3 mal aufgerufen.
Das Konsolenprotokollbild:
1. bevorzugteLayoutAttributesFittingAttributes :
Der layoutAttributes.frame.size.height ist aktuelle Stand 57.5 .
2. bevorzugteLayoutAttributesFittingAttributes :
Die Zellenrahmenhöhe wurde auf 534,5 geändert erwartungsgemäß . Die Sammlungsansicht ist jedoch immer noch gleich hoch.
3. PreferredLayoutAttributesFittingAttributes :
Sie können sehen, dass die Höhe der Sammlungsansicht von 0 auf 477 geändert wurde .
Das Verhalten ist ähnlich wie beim Scrollen:
Am Anfang dachte ich, diese Methode rufe nur einmal auf. Also habe ich wie folgt codiert:
Diese Linie:
führt zu einer Endlosschleife des Systemaufrufs und einem Absturz der App.
Bei jeder geänderten Größe werden die bevorzugten LayoutAttributesFittingAttributes aller Zellen immer wieder überprüft, bis sich die Positionen aller Zellen (dh Frames) nicht mehr ändern.
quelle
Zusätzlich zu den obigen Antworten
So stellen Sie sicher stellen Sie estimatedItemSize Eigenschaft UICollectionViewFlowLayout bis zu einem gewissen Größe und nicht implementieren sizeForItem: atIndexPath Delegatmethode.
Das ist es.
quelle
Wenn Sie die UICollectionViewDelegateFlowLayout-Methode implementieren:
- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath
Wenn Sie anrufen
collectionview performBatchUpdates:completion:
, wird die GrößenhöhesizeForItemAtIndexPath
anstelle von verwendetpreferredLayoutAttributesFittingAttributes
.Der Renderprozess von
performBatchUpdates:completion
wird die Methode durchlaufen,preferredLayoutAttributesFittingAttributes
aber Ihre Änderungen werden ignoriert.quelle
Wem auch immer es helfen mag,
Ich hatte diesen fiesen Absturz, wenn
estimatedItemSize
eingestellt war. Auch wenn ich 0 in zurückgegeben habenumberOfItemsInSection
. Daher waren die Zellen selbst und ihr automatisches Layout nicht die Ursache des Absturzes ... Die collectionView stürzte nur ab, auch wenn sie leer war, nur weilestimatedItemSize
auf Selbstgröße eingestellt war.In meinem Fall habe ich mein Projekt von einem Controller mit einer CollectionView zu einem CollectionViewController neu organisiert und es hat funktioniert.
Stelle dir das vor.
quelle
collectionView.collectionViewLayout.invalidateLayout()
danach anzurufencollectionView.reloadData()
.Für alle, die alles ohne Glück versucht haben, ist dies das einzige, was es für mich zum Laufen gebracht hat. Versuchen Sie für die mehrzeiligen Beschriftungen in der Zelle, diese magische Linie hinzuzufügen:
Mehr Infos: hier
Prost!
quelle
Die obige Beispielmethode wird nicht kompiliert. Hier ist eine korrigierte Version (aber nicht getestet, ob es funktioniert oder nicht.)
quelle
Weitere Informationen aktualisieren:
Wenn Sie verwenden
flowLayout.estimatedItemSize
, schlagen Sie vor , iOS8.3 spätere Version zu verwenden. Vor iOS8.3 stürzt es ab[super layoutAttributesForElementsInRect:rect];
. Die Fehlermeldung lautet*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
Zweitens führt in der iOS8.x-Version dazu,
flowLayout.estimatedItemSize
dass andere Einstellungen für das Einfügen von Abschnitten nicht funktionierten. dh Funktion :(UIEdgeInsets)collectionView:layout:insetForSectionAtIndex:
.quelle
Die Lösung umfasst 4 wichtige Schritte:
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
contentView
an die Ränder der Zelle, da diescontentView
die Selbstgröße verhindert, da das automatische Layout nicht aktiviert ist.collectionView(:cellForItemAt:)
, um die Breite von contentView auf die Breite von collectionView zu beschränken.Es passiert wie folgt; Wir setzen die
maxWidth
Variable der Zelle auf die Breite von CollectionView beicollectionView(:cellForItemAt:)
und inmaxWidth
derdidSet
Methode von widthAnchor.constant auf maxWidth.Da Sie die Selbstgröße von UITextView aktivieren möchten, müssen Sie einen zusätzlichen Schritt ausführen:
4. Berechnen Sie die heightAnchor.constant von UITextView und legen Sie sie fest.
Wenn also die Breite von contentView festgelegt wird, passen wir die Höhe von UITextView entlang in
didSet
an anmaxWidth
.In UICollectionViewCell:
Mit diesen Schritten erhalten Sie das gewünschte Ergebnis. Hier ist eine vollständige Übersicht
Vielen Dank an Vadim Bulavin für seinen klaren und aufschlussreichen Blog-Beitrag - Collection View Cells Self-Sizing: Schritt für Schritt Tutorial
quelle
Ich habe versucht, zu verwenden,
estimatedItemSize
aber es gab eine Reihe von Fehlern beim Einfügen und Löschen von Zellen, wenn dieestimatedItemSize
nicht genau der Höhe der Zelle entsprachen. Ich hörte auf zu setzenestimatedItemSize
und implementierte dynamische Zellen mithilfe eines Prototyps. So geht's:Erstellen Sie dieses Protokoll:
Implementieren Sie dieses Protokoll in Ihrer Gewohnheit
UICollectionViewCell
:Passen Sie nun Ihren Controller an
UICollectionViewDelegateFlowLayout
dieses Feld an und geben Sie Folgendes ein:Es wird als Prototypzelle verwendet, um Daten zu binden und dann zu bestimmen, wie sich diese Daten auf die Dimension auswirken, für die Sie dynamisch sein möchten
Endlich, das
UICollectionViewDelegateFlowLayout's
collectionView(:layout:sizeForItemAt:)
muss das umgesetzt werden:und das ist es. Das Zurückgeben der Zellengröße
collectionView(:layout:sizeForItemAt:)
auf diese Weise, ohne dass ich sie verwenden mussestimatedItemSize
, und das Einfügen und Löschen von Zellen funktioniert einwandfrei.quelle