使用 contentLayoutGuide 进行约束

Using contentLayoutGuide for constraints

在观看了 WWDC 关于新 UI 的高级功能的 session 之后,我尝试在 OSX 10.10 中使用 NSTextView 和新的 Vibrant 主题.我的文本视图没有放置在与标题栏相邻的位置,因此我将内容视图设置为全尺寸,这样我就可以将文本视图放在标题栏下方。

我的问题是我在文本视图和标题栏之间有一个 NSView,它应该直接放在标题栏下面,但我无法让自动布局为我做这件事。在视频中,他们使用 NSWindow:

中的新 contentLayoutGuide 属性 给出了示例代码
NSLayoutConstraint *topEdgeConstraint = [NSLayoutConstraint constraintWithItem:myView attribute: NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:window.contentLayoutGuide attribute:NSLayoutAttributeTop];

但是我无法让它工作,每当我尝试安装约束时 Xcode 都会给我

Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal.

我知道示例中使用的 window 属性 不在视图的子树中,因为视图位于 window 内,但我应该如何访问contentLayoutGuide 属性?

目前我正在尝试在子类 NSWindow-awakeFromNib 方法中添加约束。可能是错误的方法?

提前致谢

编辑:此解决方案不再可接受,因为 OS X El Capitan 在 window 框架中具有不同的视图层次结构。寻找 他建议使用在 Yosemite.

中引入的新 NSLayoutConstraint 方法和属性(约束激活)

我昨天遇到了同样的问题。

遗憾的是,文档中缺少有关放置此约束的位置的信息。新的 Xcode 'Capture View Hierarchy' 功能来拯救!

当您约束两个视图的某些属性时,您必须将结果约束放在这些视图的第一个共同祖先上。这是一个基本的自动布局规则。

在您的代码中,您引用了 window.contentLayoutGuide,它声明为 id,但实际上是一个 NSContentLayoutView。 运行 您的应用程序并捕获视图层次结构。这是您应该在 Yosemite:

上获得的内容

您必须将约束添加到 NSThemeFrame 视图,因为这是子树同时包含您的 myViewNSContentLayoutView 的第一个祖先。这个私有视图由 NSWindow 管理,没有明显的 属性 从 window 实例中获取它,但我们可以轻松地遍历视图层次结构。

这是一个完整的代码示例:

NSWindow* window = <Get the window>;

NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem: myView attribute: NSLayoutAttributeTop relatedBy: NSLayoutRelationEqual toItem: window.contentLayoutGuide attribute: NSLayoutAttributeTop];

[((NSView*)window.contentLayoutGuide).superview addConstraint: constraint];

在 Yosemite 中,约束现在有一个 'active' 属性,您可以设置它以使约束处于活动状态,而无需将其放在共同的祖先上。我认为它是专门为这种你不知道共同祖先的情况而创建的。

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem: myView attribute: NSLayoutAttributeTop relatedBy: NSLayoutRelationEqual toItem: window.contentLayoutGuide attribute: NSLayoutAttributeTop];
constraint.active = YES

我已经记录了我使用文本视图滚动到 window 标题栏下方的滚动视图的整个过程(包括 Apple 将内容限制在顶部的方法):https://whosebug.com/a/36435872/4615448

使用插图和跟踪 caret/cursor 的相同技术也适用于您。您仍然可以让您的滚动视图顶部指南转到 contentView 的顶部,然后使用 insets 使其出现在内容视图中并进入标题栏下方。您也可以在其上覆盖其他视图,只要它在它们下面延伸即可。然后,你可以适当地更新插图,它会落后于你需要的任何东西。

(我知道,这个问题很老了——你可能已经弄明白了。我来这里是为了在 El Capitan 10.11 中弄清楚同样的事情,所以我把这个留给任何人否则)。

我是 OS X 开发的新手,所以欢迎所有专业人士对这个 post 或下一个评论提出任何改进或见解。

我最近遇到了这个问题,我想今天我会分享推荐的处理方法。该技术可以在 WWDC 2016 Session 239 "Crafting Modern Cocoa Apps" 中看到。 API 自从他们发布以来已经有了变化,所以有一个转折。

以下代码通过使用 windows contentLayoutGuide 将其限制在内容视图的顶部,将名为 searchField 的 NSSearchField 放置在 title/tool-bar 区域的正下方。将以下代码添加到 NSViewController。

@IBOutlet weak var searchField: NSSearchField!
private var titleBarConstraint: NSLayoutConstraint?

override func updateViewConstraints() {
   if titleBarConstraint == nil {
      if let topAnchor = (searchField.window?.contentLayoutGuide as? NSLayoutGuide)?.topAnchor {
         titleBarConstraint = searchField.topAnchor.constraint(equalTo: topAnchor, constant: 8)
         titleBarConstraint?.isActive = true
      }
   }

   super.updateViewConstraints()
}

在 Interface Builder 中,使用自动布局定位 NSSearchField,以匹配运行时的外观。单击 NSSearchField 的顶部约束并启用 "Placeholder Remove at build time" 复选框。

contentLayoutGuide 仍然 returns Any? 但它是一个 NSLayoutGuide。这就是转折点。