我有一个NSSplitView(包含两个窗格)填充窗口的程序。左窗格是NSStackView,它包含三个nsbox。前两个字段都包含一个NSTextField,用于显示一系列天气信息,这些信息可以在每次由后台代码更新时更改长度。我已经在前两个nsbox(及其子NSTextFields)中添加了相关的约束,使它们随着文本长度的变化而展开或缩小,以适应其中文本字段的大小。第三个NSBox将填充堆栈视图中的剩余空间。
问题是,当窗口加载时,nsbox(如预期的那样)会显示在interface builder中设计的正确大小,以适合文本字段中的默认字符串。但是,当更新代码启动并将文本字段的文本更改为下载的数据(比默认字符串长)时,nsbox不会调整其高度以适应较大的文本。它们只在拆分视图的拆分器移动时更改高度。这很烦人,因为每当文本字段中的行数更改时,我都必须移动拆分器。为什么会发生这种情况?当文本比以前长或短时,如何使框更新高度以适合文本?
这很像这个问题(我找到的关于我的问题的唯一信息来源):NSScrollView with auto layout not resizing until first manual window resize,但是解决方案对我不起作用。
下面是界面的图像(同样,顶部的两个框应该调整大小以适合其文本,但这只在拆分器移动时发生)。它显示的文本比框所能显示的要长,但它们没有调整大小:
swift - 自动布局约束不会在子控件上生效,直到调整父容器的大小(切换)为止-LMLPHP

最佳答案

一个选项是创建NSBox的子类并重写intrinsicContentSize属性。在您的实现中,您将测量框的文本字段中包含的文本的高度,考虑文本字段的垂直边缘和框的相应边缘之间存在的任何垂直填充,并将计算结果作为height部分的NSSize返回值返回。然后,只要想调整框的大小,就可以调用invalidateIntrinsicContentSize
我创建了一个sample app来查看我是否可以让这个工作,我已经在这里发布了。有几个棘手的部分你应该注意:
计算文本高度
这种方法中最复杂的编码位是计算文本的高度。幸运的是,苹果有documentation告诉你如何做到这一点;下面是Swift中的情况:

// Properties of your NSBox subclass

var layoutManager: NSLayoutManager {
    return textStorage.layoutManagers.first! as! NSLayoutManager
}

var textContainer: NSTextContainer {
    return layoutManager.textContainers.first! as! NSTextContainer
}

var typesetter: NSTypesetter {
    return layoutManager.typesetter
}


// The textStorage object lies at the heart of the text stack. Create this
// object first, the rest follows.
lazy var textStorage: NSTextStorage! = {
    var initialString: String = ""
    var ts = NSTextStorage(attributedString: self.textField.attributedStringValue)

    var lm = NSLayoutManager()
    lm.typesetterBehavior = NSTypesetterBehavior.Behavior_10_2_WithCompatibility
    var tc = NSTextContainer()

    lm.addTextContainer(tc)
    ts.addLayoutManager(lm)

    return ts
    }()

为您的NSBox子类设置拥抱抵抗优先级
为了让演示正常工作,我发现需要将NSBox对象的垂直拥抱优先级和垂直压缩阻力值设置为900。swift - 自动布局约束不会在子控件上生效,直到调整父容器的大小(切换)为止-LMLPHP

10-08 06:07