如何使用Cocoa Auto Layout调整窗口的大小?

我有一个单一的自定义视图窗口,我希望自定义视图调整窗口的大小,以便它随时完全填充它。 如果我写:

NSView *contentView = [self.window contentView]; CustomView *customView = [[CustomView alloc] initWithFrame:[contentView bounds]]; [contentView addSubview:customView]; [contentView addConstraint: [NSLayoutConstraint constraintWithItem:customView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeWidth multiplier:1 constant:0]]; [contentView addConstraint: [NSLayoutConstraint constraintWithItem:customView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeHeight multiplier:1 constant:0]]; 

然后窗口不让我调整它。
如果我添加:

 [customView setTranslatesAutoresizingMaskIntoConstraints:NO]; 

然后自定义视图不会出现( drawRect:似乎永远不会被调用)。 我尝试了不同的方式(包括视觉格式@"|[customview]|" ),但我总是遇到同样的问题。 我知道可以使用较早的自动调整系统来完成,具体如下:

 [customView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; 

但我想使用Cocoa自动布局系统,我想用它来处理更复杂的情况(比如几个自定义视图总是填满窗口)。

有谁知道什么是错的,我应该如何使用自动布局系统来获得我想要的结果?

使用自动布局,至less有三种可能的方式来限制视图,以便它占据整个窗口的内容视图,适当resize。

关于超视图的视觉格式限制

 NSView *contentView = [_window contentView]; MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]]; [customView setTranslatesAutoresizingMaskIntoConstraints:NO]; [contentView addSubview:customView]; NSDictionary *views = NSDictionaryOfVariableBindings(customView); [contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[customView]|" options:0 metrics:nil views:views]]; [contentView addConstraints: [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[customView]|" options:0 metrics:nil views:views]]; 

对边的编程约束

(这应该等同于上面的视觉格式)

 + (void)addEdgeConstraint:(NSLayoutAttribute)edge superview:(NSView *)superview subview:(NSView *)subview { [superview addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:edge relatedBy:NSLayoutRelationEqual toItem:superview attribute:edge multiplier:1 constant:0]]; } 

 NSView *contentView = [_window contentView]; MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]]; [customView setTranslatesAutoresizingMaskIntoConstraints:NO]; [contentView addSubview:customView]; [[self class] addEdgeConstraint:NSLayoutAttributeLeft superview:contentView subview:customView]; [[self class] addEdgeConstraint:NSLayoutAttributeRight superview:contentView subview:customView]; [[self class] addEdgeConstraint:NSLayoutAttributeTop superview:contentView subview:customView]; [[self class] addEdgeConstraint:NSLayoutAttributeBottom superview:contentView subview:customView]; 

程序化的大小限制

 NSView *contentView = [_window contentView]; MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]]; [customView setTranslatesAutoresizingMaskIntoConstraints:NO]; [contentView addSubview:customView]; [contentView addConstraint: [NSLayoutConstraint constraintWithItem:customView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeWidth multiplier:1 constant:0]]; [contentView addConstraint: [NSLayoutConstraint constraintWithItem:customView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeHeight multiplier:1 constant:0]]; 

第三种方法是问题中列出的方法,如果还有进一步的限制,它可能不起作用。 例如,没有:

 [customView setTranslatesAutoresizingMaskIntoConstraints:NO]; 

还应用了原始的自动resize掩码,这会导致问题中描述的行为:窗口未被resize。

正如Regexident所提到的,你可以使用:

 [_window visualizeConstraints:[contentView constraints]]; 

debugging自动布局。 检查控制台输出也是值得的。

@ Bavarious的答案是好的,我只会添加更多的东西。

学习使用内置的debugging支持非常重要! 随着更多的发展,希望你总是能够在第一枪的时候获得一切是不现实的。 这是自动布局的一个主要问题,所以我们花费了大量的精力来进行debugging。 简要地说:

  1. 确定一个错误的地方。 从gdb调用方法 – [NSView _subtreeDescription]和/或传递参数-NSShowAllViews YES可以帮助识别哪个视图是错误的。
  2. 确定错误或缺失的约束或约束。 – [NSLayoutConstraint constraintsAffectingLayoutForOrientation:]有助于为您提供一组更小的约束。 – [NSWindow visualizeConstraints:]可以帮助您了解这些约束什么,您可以从中看出哪些不是您想要的。 它也会告诉你,如果你的布局不明确(没有足够的限制)。
  3. 确定错误约束来自哪里。 乐器中的Cocoa Layout模板就像Leaks乐器 – 它会告诉你约束的生命周期中的所有事件,比如创build它的地方,添加到窗口,修改等。所以一旦你知道了什么约束是问题,使用Instruments中的search字段来过滤只是查看该约束,并且您可以看到所有生命周期事件的回溯,并找出你做了什么你不想要的东西。

通常这种问题你会发布(我的东西不起作用!)将不足以让人们知道什么是错的,这是使用debugging的重要原因之一。 查看WWDC 2011会议video(全部免费)和文档以了解更多信息。

Buuuuut我实际上可以告诉这次出了什么事。 :-)在closurestranslatesAutoresizingMaskIntoConstraints之前,你比你想要的更受限制 – 视图的宽度和高度也被固定,这就是为什么窗口无法resize。 当你关掉它之后,你的布局不明确,因为你没有把你的视线固定在任何东西上! 你曾经说过应该有多大(与superview相同),但不是它应该在的地方。

cocoa框架,主要的自动布局作者

您可以使用布局锚以非常容易阅读的格式创build约束:

Swift2代码

 func fit(childView: UIView, parentView: UIView) { childView.translatesAutoresizingMaskIntoConstraints = false childView.topAnchor.constraintEqualToAnchor(parentView.topAnchor).active = true childView.leadingAnchor.constraintEqualToAnchor(parentView.leadingAnchor).active = true childView.trailingAnchor.constraintEqualToAnchor(parentView.trailingAnchor).active = true childView.bottomAnchor.constraintEqualToAnchor(parentView.bottomAnchor).active = true } 

使用:

 parrentView.addSubview(childView) fit(childView, parentView: parrentView) 

我发现-drawRect:在框架矩形为0,0,0,0的情况下不会被调用。 不希望的约束似乎导致框架变成0,0,0,0。