Autolayout支持自定义文本视图

问题描述 投票:1回答:1

这个问题是关于使用约束支持可变高度的自定义文本视图,以及使用视图的intrinsicContentSize进行自动布局。在您点击“重复”按钮之前,请听我说。

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

我创建了一个简化问题的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'打开)。它的intrinsicContentSize报告单行上文本的整个宽度(即使它比可用的宽度长得多),但它以某种方式调整到正确的宽度。调整大小后,intrinsicContentWidth仍会报告完整的单行宽度,但会调整高度以考虑多行。在某些地方我有一些神奇的东西。

我已阅读每一行相关文档。如果有关于该主题的博客文章,我可能已经阅读过了。如果在这个主题上有关于SO的问题,我可能已经阅读过了。如果你写了一本关于这个主题的书,我可能已经买了它。所有这些来源都可以解决我遇到的问题,但他们都没有回答如何处理这种特殊情况的问题。绝望。

更新:

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

enter image description here

但是,当插入自调整表视图时,自定义视图正确匹配其单元格的宽度,但不调整单元格以遵循固有高度。如果将自定义视图的底部约束更改为可选(例如,使用> =关系),则自定义视图会缩小到正确的高度,但单元格视图仍保持固定。如何说服单元格视图缩小其高度以尊重其子视图的intrinsicContentSize.height?

enter image description here

macos autolayout nstextview intrinsic-content-size
1个回答
1
投票

我有一个解决你的问题的方法,虽然它可能不是最佳的,因为我没有太多的macos细节经验。所以,首先,让我们定义表视图应该使用自动行高:

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来重新计算行高。我希望你或其他人能提出建议:)

这三个调整导致正确重新计算细胞高度:enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.