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
。
我有自定义的、层支持的 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
。