2014-01-18 79 views
7

我需要NSTableView的和動態的行高一點點幫助基於視圖的NSTableView的,讓行高度依賴於內容

我有什麼:基於視圖

單列NSTableView的綁定到陣列控制器。每個NSTableCellView包含三個子視圖:NSImageView,NSTextField(單行)和NSTextField(多行)。基本上,這是一個聊天界面,所以你會有一個消息,發件人和頭像列表。

我想要什麼來實現的:

當文本比該行的最小高度更長的時間,該行擴展以適應內容。就像iMessage一樣,氣泡也會擴展以適應消息。

......這似乎是一件非常自然的事情,但在我找到的所有相關解決方案中,(Ref 1,Ref 2),其中沒有一個適合我。

參考文獻2看起來飛馳的書面但沒有適用於我的應用程序,因爲示例項目使用第三方自動佈局代碼和整個事情是專爲iOS。參考文獻1給出了一個非常有希望的解決方案,用英文寫成。我嘗試使用解決方案中描述的「虛擬視圖」進行設置,但未能正確更改和測量高度。

這裏是我的代碼tableView:heightOfRow:,_samplingView是虛擬視圖,它具有工作約束並且與tableView中的虛擬視圖相同。

- (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; 

} 

結果:所有行高度保持不變,不知何故當我改變的_samplingView的寬度,它不會重新大小messageCell的大小。我認爲自動佈局會照顧這種壓縮/擴展,並允許我測量高度。的確,我很困惑。

編輯:供參考,這是我的看法是什麼樣子

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

你有沒有找到解決方案? –

+0

@Jai,我刺傷了它。 – stevesliva

回答

0

你需要調用的tableView的noteHeightOfRowsWithIndexesChanged:方法時的samplingView變化的寬度。這個方法在你的「參考文獻1」中提到。正如它在該方法的文檔中所述:

如果委託實現tableView:heightOfRow:此方法立即使用委託提供的行高重新平鋪表視圖。

對於基於NSView的表格,此方法將進行動畫處理。要關閉動畫,請創建一個NSAnimationContext分組並將持續時間設置爲0.然後調用此方法並結束分組。

表視圖有緩存行高。從概念上講,如果要更改行高度,則必須將高度標記爲髒,以獲取您爲指定的行重新調用實施的委託方法。沒有任何東西像使用KVO的可可綁定來監視影響rowHeight的所有keyPath中的更改,至少在默認情況下不會。

1

首先,你不應該設置邊界的虛擬視圖。如果您沒有使用自動佈局,您可以設置框架

鑑於您正在使用自動佈局,您不應該這樣做。您應該臨時向限制其寬度的虛擬視圖添加一個約束。

然後,不要撥打-display。撥打-layoutSubtreeIfNeeded,然後查詢虛擬視圖的fittingSize。行高應該是從fittingSize開始的高度。我不確定你爲什麼試圖將其基於messageCell的高度加上一些任意的魔術數字。不應該有必要訪問文本字段或其單元格。

你說你有單元格視圖正常工作的限制。但是,您需要確保您具有使單元視圖的高度足以容納子視圖的約束條件。這可能是一個問題,因爲表視圖將控制真實(非虛擬)單元視圖的高度,並且如果表視圖暫時使其太短而無法保持具有所需間距的子視圖,則會得到不可滿足的約束錯誤。因此,解決方案是將單元視圖底部(或高度)上的垂直約束的優先級降低到低於1000(必需)。它可能是250(低)。它只需要大於50,即NSLayoutPriorityFittingSizeCompression。這是fittingSize暫時用來儘可能減小視圖的約束條件的優先級。

這應該得到最初內容的正確高度。

作爲參考文獻1(和stevesilva)筆記,您需要以某種方式觀察變高度多行文本字段內容的變化。當它發生變化時,您需要通過調用-noteHeightOfRowsWithIndexesChanged:來告訴表視圖行高(可能已更改)。

最後,你應該努力使-tableView:heightOfRow:儘可能高效。因此,我建議您在第一次請求任何行時計算所有行高並緩存它們。 -tableView:heightOfRow:應該只是從緩存中返回一個值。因此,當您觀察到消息已更改時,應該計算該行的新高度並將其與高速緩存的高度進行比較。當且僅當高度實際發生變化 - 並非所有對內容的更改都會改變高度 - 將新值存儲在緩存中並告訴表格高度已更改。

+0

哦,是的,當你想要框架時使用邊界...這是殺手。可能是整個問題。 – stevesliva

相關問題