NSScrollView 剪辑文档视图而不是允许它滚动

NSScrollView clips document view instead of allowing it to scroll

我有自定义的、层支持的 NSView 作为 NSScrollView 的文档视图。滚动视图在 NSSplitView 内,它本身使用约束来确保它填充整个 window.

自定义视图的边界从未明确设置。然而,在某一时刻,背衬层的边界被设置为包含每个子层。明确设置边界没有帮助。

当我调整 window 大小时,滚动视图剪辑了我的自定义视图,我发现自己无法滚动:

当我调试我的视图时,我发现调整 window 的大小也会调整自定义视图框架的大小。我真的不知道这是否正常。我的自动调整大小掩码是 .ViewMinYMargin,如果关闭则为 translatesAutoresizingMaskIntoConstraints(但如果我打开它似乎没有任何改变)。

考虑到 Apple guide 中基本上没有关于如何使滚动工作的说明,我一定遗漏了一些相当简单的东西。有人知道吗?

发生这种情况是因为对自动布局约束的误解。自定义视图的每个边缘都被限制为与剪辑视图边缘的距离为 0。这有效地将视图的大小设置为裁剪视图的大小,防止滚动,因为它使裁剪的大小看起来像是自定义视图的自然大小。

解决方案是仅约束左、上和右边缘,并使下边缘自由。相反,我对自定义视图进行了 height 约束,并以编程方式将其 constant 值设置为我的视图内容(动态生成)的大小。

LayerBackedView 的示例代码:

class LayerBackedView: NSView {
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.wantsLayer = true
    }

    override var flipped: Bool {
        // hug top of scroll view if not high enough to fill it entirely
        return true
    }

    private var heightConstraint: NSLayoutConstraint {
        let firstConstraint = constraints[0] as! NSLayoutConstraint
        assert(firstConstraint.firstAttribute == .Height)
        return firstConstraint
    }

    override func awakeFromNib() {
        let red = CALayer()
        red.anchorPoint = CGPointMake(0, 0)
        red.backgroundColor = CGColorCreateGenericRGB(1, 0, 0, 1)
        red.borderWidth = 2
        red.borderColor = CGColorCreateGenericGray(0, 1)
        layer!.addSublayer(red)

        // set height constraint to whatever you need it to be
        let desiredHeight: CGFloat = 200
        heightConstraint.constant = desiredHeight
        red.frame = CGRectMake(0, 0, bounds.width, desiredHeight)
    }
}

LayerBackedView 的约束(高度值无关紧要,因为我们以编程方式更改它,约束只需要存在):

尺寸约束被添加到视图本身,但间距约束被添加到父视图。这意味着在四个约束中,高度约束将是视图内的唯一约束(这就是为什么我们可以做到 constraints[0] as! NSLayoutConstraint)。如果这不是您的情况,您可以改为 @IBOutlet