自动布局支持自定义文本视图

时间:2019-03-04 21:52:24

标签: macos autolayout nstextview intrinsic-content-size

这个问题是关于使用约束和自动布局的该视图的nativeContentSize支持高度可变的自定义文本视图。在单击该“重复”按钮之前,请先听我说。

我有一个自定义文本视图(从头开始,继承自NSView)。它支持许多常用的NSTextView功能,其中最相关的是多行,并根据可用宽度来布局其内容。它构建的应用程序将几个这些文本视图加载到表视图的每一行中。问题是高度没有根据其固有的ContentSize正确设置。

我创建了一个sample project来简化问题。它使用带有固定数量和大小的字符的“伪”文本视图,用于确定所需的宽度/高度。在该示例中,有一列的表格视图,其单元格视图只有一个子视图,即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”处于打开状态)。它的nativeContentSize在一行上报告文本的完整宽度(即使它比可用宽度长得多),但是它还是以某种方式被调整为正确的宽度。调整大小后,internalContentWidth仍将报告完整的单行宽度,但是会调整高度以考虑多行。我无法神通的地方有些魔法。

我已经阅读了相关文档的每一行。如果有关于该主题的博客文章,我可能已经读过。如果您对此主题有任何疑问,我可能已经读过。如果您写了有关该主题的书,我可能已经买了。所有这些来源都嘲笑我遇到的问题,但是没有一个回答如何处理这种特殊情况的问题。绝望。

更新:

在阅读Jonathon Mah(http://devetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.html)的一篇旧博客文章之后,我创建了一个使用他的方法的示例。这里的another project模仿了他的技术并且可以正常工作。这是应用程序的顶部。这是一个固定的容器视图,可以通过滑块进行调整。拼凑而成的是自定义视图的伪字符,其背景是粉红色。

enter image description here

但是,当将自定义视图插入到自调整大小的表格视图中时,它会正确匹配其单元格的宽度,但是该单元格未进行调整以符合固有高度。如果将自定义视图的底部约束更改为可选(例如,具有> =关系),则自定义视图确实会缩小到正确的高度,但是单元格视图保持固定。如何说服单元格视图缩小其高度,以尊重其子视图的nativeContentSize.height?

enter image description here

1 个答案:

答案 0 :(得分:1)

我对您的问题有解决方案,尽管它可能不是最佳选择,因为我对macOS的具体经验还不足。因此,首先,让我们定义表格视图应使用自动行高:

override func awakeFromNib() {
    super.awakeFromNib()
    tableView.usesAutomaticRowHeights = true
}

在第二个示例中,tableView插座未连接到TableViewController,但可能没有连接,所以请不要忘记连接它。

现在,在您的WrappingCellView中,您将覆盖layout(),但是为preferredMaxLayoutWidth设置的值不正确。我认为应该是超级视图的宽度:

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重新计算行高。希望您或其他人可以提出一些建议:)

这三个调整可正确重新计算像元高度: enter image description here