使用contentLayoutGuide进行约束

时间:2015-02-11 23:24:57

标签: objective-c xcode macos cocoa osx-yosemite

我在WWDC上观看有关新UI高级功能的会话后,尝试在OSX 10.10中使用带有新Vibrant主题的NSTextView。我的文本视图未放置在标题栏旁边,因此我将内容视图设置为完全大小,以便将文本视图放在标题栏下方。

我的问题是我在文本视图和标题栏之间有一个NSView,它应该直接放在标题栏下方,但我无法通过自动布局为我这样做。在视频中,他们使用contentLayoutGuide中的新NSWindow属性提供此示例代码:

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

但是每当我尝试安装Xcode给我的约束

时,我都无法使用它
  

无法在视图上安装约束。约束是否引用了视图子树之外的内容?这是非法的。

我得到示例中使用的window属性不在视图的子树中,因为视图放在窗口内但我应该如何访问contentLayoutGuide属性?

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

提前致谢

4 个答案:

答案 0 :(得分:8)

在Yosemite中,约束现在具有“活动”属性,您可以将其设置为使约束处于活动状态而不将其置于共同的祖先上。我认为它是专门针对这样的情况创建的,你不知道共同的祖先。

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

答案 1 :(得分:2)

我最近遇到了这个问题,并认为我今天会分享推荐的处理方法。可以在WWDC 2016大会239“制作现代可可应用程序”中看到该技术。自从发布以来,API发生了一些变化,因此有所不同。

以下代码通过使用Windows contentLayoutGuide将NSSearchField约束在内容视图的顶部,将其命名为searchField放置在标题/工具栏区域的正下方。以下代码已添加到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的顶部约束,然后启用“在构建时删除占位符”复选框。

contentLayoutGuide仍返回Any?,但这是一个NSLayoutGuide。那是曲折。

答案 2 :(得分:0)

编辑:由于OS X El Capitan在窗口框架中具有不同的视图层次结构,因此该解决方案不再可接受。寻找sam's answer,他建议使用在Yosemite中引入的新的NSLayoutConstraint方法和属性(约束激活)。

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

不幸的是,文档缺少有关放置此约束的位置的信息。新的Xcode'捕获视图层次结构'救援的特色!

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

在您的代码中,您引用window.contentLayoutGuide,声明为id,但实际上是NSContentLayoutView。运行应用程序并捕获视图层次结构。以下是优胜美地的内容:

enter image description here

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

以下是完整的代码示例:

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];

答案 3 :(得分:0)

我已经记录了我使用textview滚动浏览滚动浏览窗口标题栏的整个过程(包括Apple将事情限制在顶部的方法):{{3} }

使用插图和跟踪插入符/光标的相同技术也适用于您。您仍然可以使您的scrollview顶部指南转到contentView的顶部,然后使用insets使其显示在内容视图中并转到标题栏下方。您可以在其上覆盖其他视图,只要它在它们下面扩展即可。然后,你可以适当地更新插图,它会落后于你需要的任何内容。

(我知道,这个问题已经很久了 - 你可能已经知道了。我来到这里试图在El Capitan 10.11中找出同样的东西,所以我把它留在这里对于任何其他人。)

我对OS X开发相对较新,所以欢迎所有专业人士对此帖或下一篇文章发表评论,并注明任何改进或见解。