2014-01-18 6 views
7

Ich brauche ein wenig Hilfe bei NSTableView und dynamischen ZeilenhöheView-basierte NSTableView, stellen Zeilenhöhe abhängig von Inhalt

Was ich habe:

eine einspaltige Ansicht basierte NSTableView an ein gebundenes Array-Controller. Jede NSTableCellView enthält drei Teilansichten: NSImageView, NSTextField (einzelne Zeile) und NSTextField (mehrzeilig). Im Grunde ist dies eine Chat-Oberfläche, so dass Sie eine Liste mit Nachrichten, Absendern und Avataren haben.

Was ich will, erreichen:

Wenn der Text länger ist als Mindesthöhe der Reihe, erweitert die Reihe Inhalt passen. Ähnlich wie bei iMessage erweitern sich die Bläschen, um der Nachricht zu entsprechen.

... das scheint eine sehr natürliche Sache zu sein, aber von allen relevanten Lösungen, die ich online fand, (Ref 1, Ref 2), nichts von denen funktioniert für mich.

Ref 2 sieht fantastisch aus, aber das trifft nicht auf meine Anwendung zu, da das Beispielprojekt einen Layoutcode von Drittanbietern verwendet und das Ganze für iOS entworfen wurde. Ref 1 hat eine vielversprechende Lösung geschrieben, gut, Englisch. Ich habe versucht, es mit einer "Dummy-Ansicht" einzurichten, wie in der Lösung beschrieben, konnte aber die Höhe nicht richtig ändern und messen.

Hier ist mein Code für tableView:heightOfRow:, _samplingView ist die Dummy-Ansicht, die Arbeitseinschränkungen hat und identisch mit der in tableView ist.

- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row 
{ 
    NSTextField *textField; 
    NSTextFieldCell *messageCell; 
    for (NSView *subview in [_samplingView subviews]) { 
     if ([[subview identifier] isEqualToString:@"message"]) { 
      textField = (NSTextField*)subview; 
      messageCell = ((NSTextField*)subview).cell; 
     } 
    } 
    Message *message = [[_messagesArrayController arrangedObjects] objectAtIndex:row]; 
    _samplingView.objectValue = message; 

    CGFloat width = [[[tableView tableColumns] objectAtIndex:1] width]; 
    [_samplingView setBounds:NSMakeRect(0, 0, width, CGFLOAT_MAX)]; 
    [_samplingView display]; 

    CGFloat optimalHeight = 10 + [messageCell cellSize].height; //messageCell's size stays the same when I change samplingView to try to measure the height 
    return optimalHeight; 

} 

Ergebnis: alle Zeilenhöhen gleich bleiben, irgendwie, wenn ich die Breite von _samplingView ändern, ist es nicht die Größe neu messageCell ‚s Größe. Ich dachte Auto-Layout würde sich um diese Komprimierung/Expansion kümmern und mir erlauben, die Höhe zu messen. In der Tat bin ich sehr verwirrt.

Edit: als Referenz, ist es das, was meiner Ansicht nach wie

 +-----------+---------------------------------------------------+ 
    |   | NSTextField          | 
    |NSImageView| sender           | 
    | avatar +---------------------------------------------------+ 
    |   |             | 
    |   | NSTextField (multiline)       | 
    +-----------| message           | 
    |   |             | 
    |   | (high compression/hugging priority)    | 
    |   | (this view should decide the height of row)  | 
    |   |             | 
    +-----------+---------------------------------------------------+ 
+0

Haben Sie jemals die Lösung dafür gefunden? –

+0

@Jai, ich habe einen Stich gemacht. – stevesliva

Antwort

0

Sie die noteHeightOfRowsWithIndexesChanged: Methode, wenn die Breite der samplingView Änderungen des Tableview anrufen müssen aussieht. Diese Methode wird in Ihrem "Ref 1" erwähnt. Wie es in der Dokumentation der Methode heißt:

Wenn der Delegat TableView implementiert: heightOfRow: diese Methode kachelt die Tabellenansicht sofort mit den Zeilenhöhen der Delegate bietet.

Bei NSView-basierten Tabellen wird diese Methode animiert. Um die Animation zu deaktivieren, erstellen Sie eine NSAnimationContext-Gruppierung und legen Sie die Dauer auf 0 fest. Rufen Sie dann diese Methode auf und beenden Sie die Gruppierung.

In der Tabellenansicht sind die Zeilenhöhen im Cache gespeichert. Wenn Sie eine Zeilenhöhe ändern möchten, müssen Sie die Höhe konzeptionell als schmutzig markieren, um die von Ihnen implementierte Delegate-Methode für die von Ihnen angegebenen Zeilen erneut aufzurufen. Es gibt nichts wie Kakaobindungen, die KVO verwenden, um nach Änderungen in allen keyPaths zu suchen, die die rowHeight betreffen, zumindest nicht standardmäßig.

1

Zuerst sollten Sie die Grenzen der Dummy-Ansicht nicht festlegen.Wenn Sie kein automatisches Layout verwenden würden, würden Sie den Rahmen einstellen.

Angesichts der Tatsache, dass Sie Auto-Layout verwenden, sollten Sie auch nicht tun. Sie sollten der Dummy-Ansicht vorübergehend eine Einschränkung hinzufügen, die ihre Breite einschränkt.

Dann rufen Sie nicht -display. Rufen Sie an und fragen Sie dann die fittingSize der Dummy-Ansicht ab. Die Zeilenhöhe sollte die Höhe von fittingSize sein. Ich bin nicht sicher, warum Sie versuchen, es auf der Höhe des messageCell plus irgendeine willkürliche magische Zahl zu basieren. Es sollte nicht notwendig sein, auf das Textfeld oder seine Zelle zuzugreifen.

Sie sagen, Sie haben die Einschränkungen für die Zellenansicht ordnungsgemäß funktioniert. Sie müssen jedoch sicherstellen, dass Sie Einschränkungen haben, die die Höhe der Zellenansicht groß genug machen, um die Unteransichten aufzunehmen. Dies kann ein Problem sein, da die Tabellenansicht die Höhe der realen (nicht-dummy) Zellenansicht steuert und wenn die Tabellenansicht es vorübergehend zu kurz macht, um die Teilansichten mit dem gewünschten Abstand zu halten, werden unerfüllbare Einschränkungen auftreten Fehler. Daher besteht die Lösung darin, die Priorität der vertikalen Beschränkung für den Boden (oder die Höhe) der Zellenansicht auf unter 1000 zu reduzieren (erforderlich). Es könnte 250 (niedrig) sein. Es muss nur größer als 50 sein, also NSLayoutPriorityFittingSizeCompression. Das ist die Priorität der Einschränkungen, die fittingSize vorübergehend verwendet, um die Ansicht so klein wie möglich zu machen.

Das sollte die richtige Höhe für den ersten Inhalt bekommen.

Als Ihre Ref 1 (und stevesilva) Notizen, müssen Sie Änderungen im Inhalt Ihres mehrzeiligen Textfelds variabler Höhe irgendwie beobachten. Wenn es sich ändert, müssen Sie der Tabellenansicht mitteilen, dass sich die Zeilenhöhe (möglicherweise) geändert hat, indem Sie -noteHeightOfRowsWithIndexesChanged: darauf aufrufen.

Schließlich sollten Sie sich bemühen, -tableView:heightOfRow: so effizient wie möglich zu machen. Daher schlage ich vor, dass Sie alle Zeilenhöhen berechnen, wenn Sie das erste Mal angefordert werden, und cachen Sie sie. -tableView:heightOfRow: sollte nur einen Wert aus dem Cache zurückgeben. Wenn Sie feststellen, dass sich eine Nachricht geändert hat, sollten Sie daher eine neue Höhe für diese Zeile berechnen und sie mit der zwischengespeicherten Höhe vergleichen. Wenn und nur wenn sich die Höhe tatsächlich geändert hat - nicht alle Änderungen am Inhalt ändern die Höhe - speichern Sie den neuen Wert im Cache und teilen Sie der Tabelle mit, dass sich die Höhe geändert hat.

+0

Oh ja, Grenzen verwenden, wenn Sie Rahmen wollen ... das ist Killer. Könnte das ganze Problem sein. – stevesliva

Verwandte Themen