[英]Autolayout support for custom text view
這個問題是關於使用約束和視圖的用於自動布局的內在內容大小來支持可變高度的自定義文本視圖。 在您單擊“復制”按鈕之前,請聽我說完。
我有一個自定義文本視圖(從頭開始,從 NSView 繼承)。 它支持許多常見的 NSTextView 功能,這里最相關的是多行並根據可用寬度布置其內容。 它構建的應用程序將幾個這樣的文本視圖加載到表視圖的每一行中。 問題是高度沒有根據其內在內容大小正確設置。
我創建了一個簡化問題的示例項目。 它使用具有固定數量和字符大小的“偽”文本視圖,用於確定所需的寬度/高度。 在示例中,有一列的表視圖,其單元格視圖只有一個子視圖,即 PseudoTextView。 文本視圖固定在其單元格視圖的邊緣,並帶有一點填充。 我怎樣才能讓系統認識到文本視圖應該遵守定義寬度的約束,同時允許文本視圖在高度上增長,被單元格視圖緊緊包裹? 這是文本視圖代碼:
class PseudoTextView: NSView {
@IBInspectable var characterCount: Int = 0
@IBInspectable var characterWidth: CGFloat = 5
@IBInspectable var characterHeight: CGFloat = 8
@IBInspectable var background: NSColor = .blue {
didSet {
layer?.backgroundColor = background.cgColor
}
}
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
wantsLayer = true
layer?.backgroundColor = background.cgColor
}
override var intrinsicContentSize: NSSize {
let requiredWidth = characterWidth * CGFloat(characterCount)
let lineCount = (requiredWidth / frame.width).rounded(.up)
let usedHeight = lineCount * characterHeight
let charactersPerLine = (frame.width / characterWidth).rounded(.down)
let usedWidth = charactersPerLine * characterWidth
return NSSize(width: usedWidth, height: usedHeight)
}
此版本根據視圖的框架返回適當的大小。 這顯然不起作用,因為它是在尚未設置框架的布局的 updateConstraints 階段訪問的。 我也嘗試使用 NSView.noIntrinsicMetric 作為寬度,但這會將文本視圖驅動為零寬度並且高度永遠不會恢復。 我已經進行了大量其他嘗試,但我不會讓您厭煩所有這些。
NSTextField 做了一些不同的事情(假設 'Editable' 關閉,'Wrap' 開啟)。 它的內在內容大小在單行上報告文本的全寬(即使它比可用寬度長得多),但它以某種方式調整為正確的寬度。 調整大小后,內在內容寬度仍會報告完整的單行寬度,但會調整高度以考慮多行。 某處有一些我無法預知的魔法。
我已經閱讀了相關文檔的每一行。 如果有關於該主題的博客文章,我可能已經閱讀過。 如果有關於該主題的 SO 問題,我可能已經閱讀過。 如果你寫了一本關於這個主題的書,我可能已經買了它。 所有這些來源都在嘲笑我遇到的問題,但沒有一個回答如何處理這種特殊情況的問題。 絕望的。
更新:
在閱讀了 Jonathon Mah 的一篇舊博文( http://devetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.html )后,我創建了一個使用他的方法的示例。 這是另一個模仿他的技術並正常工作的項目。 這是應用程序的頂部。 這是一個用滑塊調整的固定容器視圖。 拼湊是自定義視圖的偽字符,其背景為粉紅色。
但是,當插入到自調整表格視圖中時,自定義視圖正確匹配其單元格的寬度,但未調整單元格以尊重固有高度。 如果您將自定義視圖的底部約束更改為可選(例如,使用 >= 關系),自定義視圖確實會縮小到正確的高度,但單元格視圖保持固定。 如何說服單元格視圖縮小其高度以尊重其子視圖的內在內容尺寸.高度?
我對您的問題有一個解決方案,盡管它可能不是最佳解決方案,因為我對 macos 的細節沒有太多經驗。 所以,首先,讓我們定義 table view 應該使用自動行高:
override func awakeFromNib() {
super.awakeFromNib()
tableView.usesAutomaticRowHeights = true
}
在您的第二個示例中, tableView 插座沒有連接到TableViewController
,但它可能應該連接,所以不要忘記連接它。
現在,在您的WrappingCellView
,您覆蓋了layout()
,但您為preferredMaxLayoutWidth
設置的值不正確。 我認為應該是superview的寬度:
override func layout() {
// 16 is used for the sake of example
wrappingView.preferredMaxLayoutWidth = (superview?.frame.width ?? 16) - 16
super.layout()
}
下一部分是我不確定的部分:
func tableViewColumnDidResize(_ notification: Notification) {
tableView.reloadData()
}
應該有更好的 API 來重新計算行高。 我希望你或其他人可以提出一些建議:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.