这个问题是关于使用约束和 View 的内在内容大小来支持可变高度的自定义 TextView 以进行自动布局。在您点击“复制”按钮之前,请先听我说完。
我有一个自定义 TextView (从头开始,继承自 NSView)。它支持许多常见的 NSTextView 功能,其中最相关的是多行并根据可用宽度布局其内容。它构建的应用程序将几个这样的 TextView 加载到 TableView 的每一行中。问题是高度没有根据其内在内容大小正确设置。
我创建了一个sample project这简化了问题。它使用“伪” TextView ,具有固定数量和大小的字符,用于确定所需的宽度/高度。在示例中,有一个一列的表格 View ,其单元格 View 只有一个 subview ,即 PseudoTextView。 TextView 通过一点填充固定到其单元格 View 的边缘。如何让系统认识到 TextView 应该遵守定义宽度的约束,同时允许 TextView 的高度增长,并被单元格 View 紧紧包裹?这是 TextView 代码:
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)
}
此版本根据 View 的框架返回适当的大小。这显然不起作用,因为它是在布局的 updateConstraints 阶段(当框架尚未设置时)访问的。我还尝试使用 NSView.noIntrinsicMetric 作为宽度,但这会将 TextView 驱动到零宽度,并且高度永远不会恢复。我还进行了大量其他尝试,但我不会一一列举让您感到厌烦。
NSTextField 做了不同的事情(假设“Editable”关闭,“Wrap”打开)。它的intrinsicContentSize 报告单行上文本的完整宽度(即使它比可用宽度长得多),但它会以某种方式调整为正确的宽度。调整大小后,intrinsicContentWidth 仍会报告完整的单行宽度,但会调整高度以考虑多行。有一些我无法预见的魔法。
我已阅读每一行相关文档。如果有关于该主题的博客文章,我可能已经阅读过。如果有关于这个主题的问题,我可能已经读过了。如果你写了一本关于这个主题的书,我可能已经买了。所有这些来源都 mock 我遇到的问题,但没有一个回答如何处理这种特殊情况的问题。绝望。
更新:
阅读 Jonathon Mah (http://devetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.html) 的旧博客文章后,我创建了一个使用他的方法的示例。这是another project模仿他的技术并且工作正常。这是应用程序的顶部部分。它是一个固定的容器 View ,可以使用 slider 进行调整。拼凑而成的是自定义 View 的伪字符,其背景是粉红色。
但是,当插入到自调整大小的 TableView 中时,自定义 View 会正确匹配其单元格的宽度,但不会调整单元格以尊重固有高度。如果将自定义 View 的底部约束更改为可选(例如,使用 >= 关系),则自定义 View 会缩小到正确的高度,但单元格 View 保持固定。如何说服单元格 View 缩小其高度以尊重其 subview 的intrinsicContentSize.height?
最佳答案
我对你的问题有一个解决方案,尽管它可能不是最佳的,因为我对 macOS 细节没有太多经验。因此,首先,我们定义 TableView 应使用自动行高:
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 来重新计算行高。我希望你或其他人可以提出一些建议:)
关于macos - 自定义 TextView 的自动布局支持,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54992110/