Ich habe eine Anwendung mit einer Ansicht, die darauf basiert NSTableView
. In dieser Tabellenansicht befinden sich Zeilen mit Zellen, deren Inhalt aus mehreren Zeilen NSTextField
mit aktiviertem Zeilenumbruch besteht. Abhängig vom Textinhalt von NSTextField
variiert die Größe der Zeilen, die zum Anzeigen der Zelle benötigt werden.
Ich weiß, dass ich die NSTableViewDelegate
Methode implementieren kann - tableView:heightOfRow:
um die Höhe zurückzugeben, aber die Höhe wird basierend auf dem Wortumbruch bestimmt, der auf dem verwendet wird NSTextField
. Die Wortumhüllung von NSTextField
basiert in ähnlicher Weise darauf, wie breit das NSTextField
ist ... was durch die Breite von bestimmt wird NSTableView
.
Soooo… ich denke meine Frage ist… was ist ein gutes Designmuster dafür? Es scheint, als wäre alles, was ich versuche, ein kompliziertes Durcheinander. Da die TableView Kenntnisse über die Höhe der Zellen erfordert, um sie auszurichten ... und die NSTextField
Kenntnisse über das Layout, um den Zeilenumbruch zu bestimmen ... und die Zelle Kenntnisse über den Wortumbruch benötigt, um die Höhe zu bestimmen ... ist es ein kreisförmiges Durcheinander ... und es macht mich wahnsinnig .
Vorschläge?
Wenn es darauf ankommt, kann das Endergebnis auch bearbeitet werden NSTextFields
, um die Größe an den darin enthaltenen Text anzupassen. Ich habe dies bereits auf der Ansichtsebene ausgeführt, aber die Tabellenansicht passt die Höhe der Zellen noch nicht an. Ich denke, sobald ich das Höhenproblem gelöst habe, werde ich das -noteHeightOfRowsWithIndexesChanged
-Methode verwenden, um die Tabellenansicht über die geänderte Höhe zu informieren ... aber dann wird der Delegierte immer noch nach der Höhe gefragt ... daher mein Dilemma.
Danke im Voraus!
quelle
Antworten:
Dies ist ein Henne-Ei-Problem. Die Tabelle muss die Zeilenhöhe kennen, da dies bestimmt, wo eine bestimmte Ansicht liegen wird. Sie möchten jedoch, dass eine Ansicht bereits vorhanden ist, damit Sie die Zeilenhöhe ermitteln können. Also, was kommt zuerst?
Die Antwort besteht darin, eine zusätzliche
NSTableCellView
Ansicht (oder eine beliebige Ansicht, die Sie als "Zellenansicht" verwenden) beizubehalten, nur um die Höhe der Ansicht zu messen. Greifen Sie in dertableView:heightOfRow:
Delegate-Methode auf Ihr Modell für 'row' zu und setzen Sie die OptionobjectValue
onNSTableCellView
. Stellen Sie dann die Breite der Ansicht auf die Breite Ihrer Tabelle ein und ermitteln Sie (wie auch immer Sie dies tun möchten) die erforderliche Höhe für diese Ansicht. Geben Sie diesen Wert zurück.Rufen Sie nicht
noteHeightOfRowsWithIndexesChanged:
in der Delegate-MethodetableView:heightOfRow:
oder aufviewForTableColumn:row:
! Das ist schlecht und wird Mega-Ärger verursachen.Um die Höhe dynamisch zu aktualisieren, müssen Sie auf die Textänderung (über das Ziel / die Aktion) reagieren und die berechnete Höhe dieser Ansicht neu berechnen. Ändern Sie jetzt nicht dynamisch die
NSTableCellView
Höhe des Objekts (oder die Ansicht, die Sie als "Zellenansicht" verwenden). Die Tabelle muss den Rahmen dieser Ansicht steuern, und Sie kämpfen gegen die Tabellenansicht, wenn Sie versuchen, sie festzulegen . Rufen Sie stattdessen in Ihrem Ziel / Ihrer Aktion für das Textfeld, in dem Sie die Höhe berechnet habennoteHeightOfRowsWithIndexesChanged:
, die Größe der einzelnen Zeile für die Tabelle auf. Angenommen, Sie haben Ihr Autoresizing-Masken-Setup direkt in Unteransichten (dh Unteransichten vonNSTableCellView
), sollte die Größe der Dinge in Ordnung sein! Wenn nicht, arbeiten Sie zuerst an der Größenänderungsmaske der Unteransichten, um die Dinge mit variablen Zeilenhöhen richtig zu machen.Vergessen Sie nicht, dass dies
noteHeightOfRowsWithIndexesChanged:
standardmäßig animiert wird. Um es nicht zu animieren:PS: Ich beantworte mehr Fragen in den Apple Dev-Foren als Stapelüberlauf.
PSS: Ich habe die ansichtsbasierte NSTableView geschrieben
quelle
tableView:heightOfRow:
richte ich meine Ersatzzellenansicht mit den Zeilenwerten ein (ich habe nur eine Spalte) und kehre zurückcellView.fittingSize.height
.fittingSize
ist eine NSView-Methode, die die minimale Größe der Ansicht berechnet, die ihre Einschränkungen erfüllt.Dies wurde in macOS 10.13 mit viel einfacher
.usesAutomaticRowHeights
. Die Details finden Sie hier: https://developer.apple.com/library/content/releasenotes/AppKit/RN-AppKit/#10_13 (Im Abschnitt "NSTableView Automatic Row Heights").Grundsätzlich wählen Sie einfach Ihr
NSTableView
oderNSOutlineView
im Storyboard-Editor aus und wählen diese Option im Größeninspektor aus:Dann stellen Sie das Material in Ihrer so ein
NSTableCellView
, dass die Zelle über obere und untere Einschränkungen verfügt, und die Größe Ihrer Zelle wird automatisch angepasst. Kein Code erforderlich!Ihre App ignoriert alle in
heightOfRow
(NSTableView
) undheightOfRowByItem
(NSOutlineView
) angegebenen Höhen . Mit dieser Methode können Sie sehen, welche Höhen für Ihre automatischen Layoutzeilen berechnet werden:quelle
TableCellView
es NICHT bearbeitet werden kann. Egal, wird in Attributen [Verhalten: Bearbeitbar] oder Bindungsinspektor [Bedingt bearbeitbar: Ja]Basierend auf Corbins Antwort (übrigens danke, dass wir etwas Licht ins Dunkel bringen):
Swift 3, View-Based NSTableView mit Auto-Layout für macOS 10.11 (und höher)
Mein Setup: Ich habe ein
NSTableCellView
, das mit Auto-Layout angelegt ist. Es enthält (neben anderen Elementen) eine mehrzeilige ZeileNSTextField
mit bis zu 2 Zeilen. Daher hängt die Höhe der gesamten Zellenansicht von der Höhe dieses Textfelds ab.Ich aktualisiere die Tabellenansicht, um die Höhe zweimal zu aktualisieren:
1) Wenn die Größe der Tabellenansicht geändert wird:
2) Wenn sich das Datenmodellobjekt ändert:
Dadurch fragt die Tabellenansicht den Delegierten nach der neuen Zeilenhöhe.
Zuerst müssen wir unser Modellobjekt für die Zeile (
entity
) und den entsprechenden Bezeichner für die Zellenansicht abrufen. Wir prüfen dann, ob wir bereits eine Ansicht für diesen Bezeichner erstellt haben. Dazu müssen wir für jeden Bezeichner eine Liste mit Zellenansichten führen:Wenn keine gespeichert ist, müssen wir eine neue erstellen (und zwischenspeichern). Wir aktualisieren die Zellenansicht mit unserem Modellobjekt und weisen es an, alles basierend auf der aktuellen Breite der Tabellenansicht neu zu gestalten. Die
fittingSize
Höhe kann dann als neue Höhe verwendet werden.quelle
cellView.bounds.size.width = tableView.bounds.size.width
eine gute Idee, die Höhe auf eine niedrige Zahl zurückzusetzen. Wenn Sie diese Dummy-Ansicht wiederverwenden möchten, wird die Anpassungsgröße durch Zurücksetzen auf eine niedrige Zahl "zurückgesetzt".Für alle, die mehr Code wünschen, ist hier die vollständige Lösung, die ich verwendet habe. Danke corbin dunn, dass du mich in die richtige Richtung gelenkt hast.
Ich musste die Höhe hauptsächlich in Bezug darauf einstellen, wie hoch ein
NSTextView
in meinemNSTableViewCell
war.In meiner Unterklasse von
NSViewController
erstelle ich vorübergehend eine neue Zelle, indem ich aufrufeoutlineView:viewForTableColumn:item:
In meinem
IBAnnotationTableViewCell
, dem Controller für meine Zelle (Unterklasse vonNSTableCellView
), habe ich eine Setup-MethodeHiermit werden alle Steckdosen eingerichtet und der Text aus meinen PDFAnnotations festgelegt. Jetzt kann ich die Höhe "einfach" berechnen mit:
.
.
quelle
Ich habe lange nach einer Lösung gesucht und mir die folgende ausgedacht, die in meinem Fall hervorragend funktioniert:
quelle
Da ich benutzerdefinierte verwende
NSTableCellView
und Zugriff auf die habe, bestandNSTextField
meine Lösung darin, eine Methode hinzuzufügenNSTextField
.quelle
Haben Sie sich RowResizableViews angesehen ? Es ist ziemlich alt und ich habe es nicht getestet, aber es kann trotzdem funktionieren.
quelle
Folgendes habe ich getan, um das Problem zu beheben:
Quelle: Schauen Sie in die XCode-Dokumentation unter "Zeilenhöhe nstableview". Sie finden einen Beispielquellcode mit dem Namen "TableViewVariableRowHeights / TableViewVariableRowHeightsAppDelegate.m".
(Hinweis: Ich betrachte Spalte 1 in der Tabellenansicht. Sie müssen Änderungen vornehmen, um woanders zu suchen.)
in Delegate.h
in Delegate.m
Die Tabellenansicht delegiert die Steuerung der Zeilenhöhe
Sie benötigen dies auch, um die neue Zeilenhöhe zu bewirken (delegierte Methode).
Ich hoffe das hilft.
Schlussbemerkung: Dies unterstützt keine Änderung der Spaltenbreite.
quelle
-[NSTableView preparedCellAtColumn:row]
Codeaufrufe, die laut den Dokumenten "nur für NSCell-basierte Tabellenansichten verfügbar sind". Die Verwendung dieser Methode in einer ansichtsbasierten Tabelle erzeugt diese Protokollausgabe zur Laufzeit: "Ansichtsbasierter NSTableView-Fehler: prepareCellAtColumn: row: wurde aufgerufen. Bitte protokollieren Sie einen Fehler mit der Rückverfolgung aus diesem Protokoll oder beenden Sie die Verwendung der Methode."Hier ist eine Lösung, die auf der Antwort von JanApotheker basiert und geändert wurde, da
cellView.fittingSize.height
für mich nicht die richtige Höhe zurückgegeben wurde. In meinem Fall verwende ich den StandardNSTableCellView
, einenNSAttributedString
für den TextField-Text der Zelle und eine einzelne Spaltentabelle mit Einschränkungen für das in IB festgelegte TextField der Zelle.In meinem View Controller erkläre ich:
In viewDidLoad ():
Schließlich für die tableView-Delegatenmethode:
mimimumCellHeight
ist eine Konstante, die für die Sicherung auf 30 gesetzt ist, aber nie verwendet wird.attributedStrings
ist mein Modellarray vonNSAttributedString
.Dies funktioniert perfekt für meine Bedürfnisse. Vielen Dank für alle vorherigen Antworten, die mich für dieses lästige Problem in die richtige Richtung gelenkt haben.
quelle
Das klingt sehr nach etwas, das ich vorher tun musste. Ich wünschte, ich könnte Ihnen sagen, dass ich eine einfache, elegante Lösung gefunden habe, aber leider nicht. Nicht aus Mangel an Versuchen. Wie Sie bereits bemerkt haben, lässt die Notwendigkeit von UITableView, die Höhe vor dem Erstellen der Zellen zu kennen, alles ziemlich kreisförmig erscheinen.
Meine beste Lösung bestand darin, die Logik in die Zelle zu übertragen, da ich zumindest isolieren konnte, welche Klasse benötigt wurde, um zu verstehen, wie die Zellen angeordnet waren. Eine Methode wie
würde bestimmen können, wie groß die Zelle sein musste. Dazu gehörte natürlich das Messen von Text usw. In einigen Fällen habe ich Methoden entwickelt, um Informationen, die mit dieser Methode gewonnen wurden, zwischenzuspeichern, die dann beim Erstellen der Zelle verwendet werden konnten. Das war das Beste, was ich mir ausgedacht habe. Es ist jedoch ein ärgerliches Problem, da es anscheinend eine bessere Antwort geben sollte.
quelle