如何使用Cocoa Auto Layout窗口调整自定义视图的大小?

Gui*_*ume 71 layout cocoa

我有一个窗口,其中包含一个自定义视图,我希望自定义视图可以随窗口调整大小,以便随时完全填充它.如果我写:

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]];
Run Code Online (Sandbox Code Playgroud)

然后窗口不允许我调整它.
如果我添加:

[customView setTranslatesAutoresizingMaskIntoConstraints:NO];
Run Code Online (Sandbox Code Playgroud)

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

[customView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
Run Code Online (Sandbox Code Playgroud)

但是我想使用Cocoa Auto Layout系统,我想将它用于更复杂的情况(比如总是填满窗口的几个自定义视图).

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

小智 107

使用自动布局,有(至少)三种可能的方式来约束视图,使其占据整个窗口的内容视图,并在适当时调整大小.

关于superview的视觉格式约束

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]];
Run Code Online (Sandbox Code Playgroud)

边缘的编程约束

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

+ (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]];
}
Run Code Online (Sandbox Code Playgroud)

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];
Run Code Online (Sandbox Code Playgroud)

大小的编程约束

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]];
Run Code Online (Sandbox Code Playgroud)

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

[customView setTranslatesAutoresizingMaskIntoConstraints:NO];
Run Code Online (Sandbox Code Playgroud)

也会应用原始自动调整大小的掩码,这会导致问题中描述的行为:窗口未调整大小.

如Regexident所述,您可以使用:

[_window visualizeConstraints:[contentView constraints]];
Run Code Online (Sandbox Code Playgroud)

调试自动布局.值得检查控制台输出.


Ken*_*Ken 47

@ Bavarious的答案很好,我只会添加一些东西.

学习使用内置的调试支持非常重要!正如许多发展一样,希望你在第一次拍摄时始终能够做到一切都是不现实的.这是自动布局的一个主要问题,因此我们花了很多精力进行调试.步骤,简要说明:

  1. 确定位于错误位置的视图.从gdb调用方法 - [NSView _subtreeDescription]和/或传递参数-NSShowAllViews YES可以帮助识别哪个视图是错误的.
  2. 确定错误或缺失的约束或约束. - [NSLayoutConstraint constraintsAffectingLayoutForOrientation:]有助于为您提供一组较小的约束.- [NSWindow visualizeConstraints:]可以帮助您了解这些约束什么,您可以从中看到哪些不是您想要的东西.它还会显示您的布局是否模糊(没有足够的约束).
  3. 确定错误约束的来源.Instruments中的Cocoa Layout模板有点像Leaks仪器 - 它会向你显示约束生命周期中的所有事件,比如它的创建位置,添加到窗口,修改等等.所以一旦你知道了什么约束是问题,使用Instruments中的搜索字段过滤到只查看该约束,您可以看到所有生命周期事件的回溯,并找出你做了一些你不想要的事情.

通常你发布的问题(我的东西不起作用!)不足以让人们知道什么是错的,这是使用调试内容的重要原因之一.有关详细信息,请参阅WWDC 2011会话视频(全民免费)和文档.

Buuuuut我实际上可以告诉这次出了什么问题.:-)在你关闭translatesAutoresizingMaskIntoConstraints,你比你想成为更多的限制-您的视图的宽度和高度是固定的为好,这也是为什么窗口不能调整大小.你把它关掉后,你的布局模糊不清,因为你没有把视线固定在任何东西上!你曾表示,它应该多大(同为上海华盈),但不是在那里它被认为是.

Cocoa Frameworks,主要自动布局作者

  • 肯,只是想在汽车布局上说出色的工作.我花了一些时间来掌握如何有效地使用它,但我已经能够用它做一些相当强大的东西.干杯! (6认同)

lar*_*rva 5

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

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
}
Run Code Online (Sandbox Code Playgroud)

使用:

parrentView.addSubview(childView)
fit(childView, parentView: parrentView)
Run Code Online (Sandbox Code Playgroud)