10.11 NSCollectionView - Bestimmen der Zellengröße dynamisch

8

AppKit Release Notes für OS X v10.11 schlägt diese Sammlung vor Die Größe von Ansichtselementen kann pro Element geändert werden:

  

Die Elementgröße kann global für alle Elemente einer CollectionView festgelegt werden (indem die Eigenschaft "itemSize" von NSCollectionViewFlowLayout festgelegt wird) oder von Element zu Element variiert werden (durch Implementierung von -collectionView: layout: sizeForItemAtIndexPath: auf dem Delegierten des CollectionView ).

In meinem Fall besteht mein CollectionViewItem aus einem einzelnen Label, das eine Zeichenfolge unterschiedlicher Länge enthält. Ich benutze die NSCollectionView, um ein Array von Strings anzuzeigen, da NSStackViews Array-Bindungen nicht unterstützen und nicht zu neuen Zeilen fließen. Das String-Array ist über einen Array-Controller an den Inhalt der NSCollectionView gebunden.

Die NIB-Datei meines Elements ist korrekt eingerichtet, die Stammansicht und das Label haben beide Content Hugging und Inhaltskomprimierungswiderstand Prioritäten von 1000, und die Kanten werden über ausgerichtet AutoLayout.

Jetzt hat die Delegate-Methode von NSCollectionViewLayout diese Signatur:

%Vor%

Meine Idee ist jetzt, den Gegenstand selbst zu greifen, einen Layout-Durchlauf darüber durchzuführen und dann die neue Gegenstandsgröße zurückzugeben.

%Vor%

Problem bei diesem Ansatz ist, dass itemAtIndexPath nil zurückgibt. Wenn ich eine Standardgröße im Null-Fall zurückgebe, wird diese Standardgröße für alle Zellen verwendet.

Wie kann ich eine NSCollectionView so einstellen, dass sie die AutoLayout-Bedingungen meines Elements berücksichtigt und für jede Zelle die berechnete Größe dynamisch verwendet?

    
Etan 01.11.2015, 08:19
quelle

1 Antwort

1

Es gibt ein Duplikat dieser Frage, das ich beantwortet habe, aber das ist wahrscheinlich das, an das es gerichtet werden sollte, da es älter ist.

Juuls Kommentar ist korrekt - die Artikel existieren nicht. sizeForItemAt wird aufgerufen, wenn die Sammlung den Delegaten nach einer bestimmten Dimension für diesen Dateneintrag fragt, mit der er den endgültigen View-Controller NSCollectionViewItem erstellt. Sie erstellen also eine Schleife, wenn Sie die Sammlung anfragen, um ein Element in der Methode zu erhalten, mit dem ein Element abgerufen werden kann.

Das Problem, das wir haben, ist, dass wir eine Dimensionierung basierend auf der Darstellung dieser Daten vornehmen wollen: die Länge einer Textbeschriftung mit richtiger Formatierung, nicht nur, sagen wir mal, die Zeichenfolgenlänge. Wir haben also ein Problem mit Huhn und Ei bekommen.

Die einzige Lösung, zu der ich gekommen bin, die schöner sein könnte, ist die folgende:

Vorbereitung

  • Unterklasse NSCollectionViewItem und sicherstellen, dass Ihre Sammlungsansicht über eine Datenquelle verfügt, die das richtige untergeordnete Element zurückgibt.
  • Verwenden Sie Einschränkungen in Ihrem XIB vollständig.
  • Ihre Unterklasse sollte eine Methode haben, die in das darzustellende Datenobjekt geladen wird - sowohl für diese als auch für Ihre Datenquellenprotokollmethoden.
  • Irgendwann vor dem ersten Aufruf von sizeForItemAt oder zu Beginn des ersten Aufrufs, falls noch nicht geschehen, erstellen Sie manuell eine Instanz Ihrer Unterklasse NSCollectionViewItem und verwenden NSNibs instantiate(withOwner:topLevelObjects:) zum Instanziieren seine XIB mit Ihrer Unterklasse als Besitzer. Speichern Sie diese Referenz als eine Art "Formatvorlage", sodass Sie sie nur einmal ausführen müssen. Delegierter war der einfachste Ort für mich.

^ Hinweis: Meine erste Route bestand darin, dies durch die makeItemWithIdentifier der Sammlung zu versuchen, aber sie war brüchiger, da die Sammlung zum Zeitpunkt der Erstellung der Dimensionierungsvorlage Elemente enthalten musste. Es konnte auch nicht während einer initialen sizeForItemAt ausgeführt werden (der Zugriff auf / das Erstellen von Elementen während eines Neuladevorgangs stürzt ab). Und ich war besorgt, dass, weil es mit der Sammlung gemacht wurde, es in der Reihe wiederverwendet werden kann und die unten stehenden Methoden nicht funktionieren oder sichtbare Objekte bearbeiten. YMMV.

In sizeForItemAt

  • Erhalten Sie das Datenobjekt direkt aus der Datenquelle. Lassen Sie das Objekt für die Größenvorlage dieses Datenobjekt mit der zuvor erwähnten Methode darstellen.
  • Greifen Sie auf das View.FittingSize der Größenvorlage zu, und geben Sie die kleinste Größe an, für die ein Element seine Einschränkungen / Prioritäten erhalten kann.

Bam! Stresstests gab es nicht, aber es gab keine Probleme, und es wurde kein Layout-Pass erstellt, sondern nur FittingSize aufgerufen. Ich habe das noch nirgendwo online gesehen, also wollte ich die vollständige Erklärung schreiben.

Ich habe das in Xamarin.Mac gemacht, also wird mein Code nicht 1: 1 sein und ich möchte nicht verstümmelt schreiben und alles durcheinander bringen.

TLDR: instanziieren Sie manuell eine NSCollectionViewItem-Unterklasse und ihre XIB, die Sie speichern und die von der Auflistung nicht verwendet wird. Während sizeForItem füllen Sie das Element, das Sie als Dimensionierungsreferenz speichern, und geben das FittingSize der Ansicht des Auflistungselements zurück.

    
NickSpag 26.01.2018 22:41
quelle