通过代码添加和设置NSLayoutConstraint

时间:2012-12-19 17:40:48

标签: objective-c macos cocoa autolayout nslayoutconstraint

NSLayoutConstraint我遇到了一些麻烦。

如果我尝试使用constant方法更改setConstant:,NSLayoutConstraint会给我一个例外。当我通过代码添加高度约束时,我只有这个问题。

首先,我得到了高度限制:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"firstAttribute = %d", NSLayoutAttributeWidth];
NSArray *filteredArray = [[self constraints] filteredArrayUsingPredicate:predicate];
return filteredArray[0];

这给了我正确的约束。我有一个NSTextField子类,这是完美的。约束在Interface Builder中设置,我可以设置和更改常量。

现在我有一个视图,我在运行时添加不同的子视图。 这些子视图位于自己的NIB中,这意味着我无法固定它们的宽度和高度。 所以我认为一旦将视图添加到superview,我就会添加约束。 这是在viewDidMoveToSuperview执行的。

// Pin Width & Height
[self addConstraint:[NSLayoutConstraint constraintWithItem:self
                             attribute:NSLayoutAttributeWidth
                             relatedBy:NSLayoutRelationEqual
                                toItem:nil
                             attribute:NSLayoutAttributeNotAnAttribute
                            multiplier:1.0f
                              constant:self.frame.size.width]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:self
                                                 attribute:NSLayoutAttributeHeight
                                                 relatedBy:NSLayoutRelationEqual
                                                    toItem:nil
                                                 attribute:NSLayoutAttributeNotAnAttribute
                                                multiplier:1.0f
                                                  constant:self.frame.size.height]];

添加了约束,我可以用NSLog确认。

"<NSLayoutConstraint:0x100605cc0 H:[ITControlPanelChildView:0x100616eb0(269)]>",
"<NSLayoutConstraint:0x100614410 V:[ITControlPanelChildView:0x100616eb0(317)]>"

现在,最后,当我尝试使用[constraint setConstant:somethingDifferent];更改约束时,我得到以下异常:

Unable to simultaneously satisfy constraints:
(
    "<NSLayoutConstraint:0x10192fcb0 V:[ITControlPanelChildView:0x10192e4f0(100)]>",
    "<NSAutoresizingMaskLayoutConstraint:0x10053ff10 h=--& v=&-- V:[ITControlPanelChildView:0x10192e4f0(317)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x10192fcb0 V:[ITControlPanelChildView:0x10192e4f0(100)]>

这正是我试图改变的约束。 任何人都可以向我解释为什么会这样吗?


修改

我刚刚看到NSAutoresizingMaskLayoutConstraint被自动添加,如果您设置[self setTranslatesAutoresizingMaskIntoConstraints:NO];,则可以停用。

如果我禁用它,它就可以。

如果我可以访问创建的NSAutoresizingMaskLayoutConstraint,那就更好了。有谁知道这是如何工作的?

2 个答案:

答案 0 :(得分:8)

正如您未包含的日志消息的其余部分所示,您已经获得了您不想要或不需要的自动调整约束。

添加子视图时可以删除这些内容。在上面使用的方法中,只需添加以下行:

self.translatesAutoresizingMaskIntoConstraints = NO;

虽然如果你在一个单独的笔尖中创建视图,它的大小是从哪里来的?它是否已经有尺寸限制你可以创建出口?

答案 1 :(得分:1)

我遇到了这个问题两次

我使用了Hillegass&amp ;;的 Cocoa Programming for Mac OSX 4th Ed 中描述的技术。普雷布尔。本书建议使用NSBox作为视图容器,并使用代码将视图切换到视图容器中。本书还包括一些方便的代码,用于手动调整外部包含窗口的大小,以保存刚刚切换到的视图。

我第一次尝试他们的技术时遇到了这个例外:

2013-01-05 22:56:05.103 MyApp[17717:303] Unable to simultaneously satisfy constraints:
(
    "<NSAutoresizingMaskLayoutConstraint:0x100141330 h=--& v=--& H:[NSView:0x10012fdf0(4)]>",
"<NSLayoutConstraint:0x1001316c0 H:[NSScrollView:0x100123ff0]-(NSSpace(20))-|   (Names: '|':NSView:0x10012fdf0 )>",
"<NSLayoutConstraint:0x1001315d0 H:|-(NSSpace(20))-[NSScrollView:0x100123ff0]   (Names: '|':NSView:0x10012fdf0 )>")

Will attempt to recover by breaking constraint 

令人沮丧的是,我不得不重构UI和重建版本(基于NSDocument而不是简单的窗口)我再次遇到了同样的问题。

如果我在子视图上将translatesAutoResizingConstraints设置为NO,则它们无法正确布局。但是那些子视图很复杂,所以它不是解决方案,因为我的窗口没有布局。但这确实可以阻止异常被抛出。

如果我在基于顶级NSDocument的窗口XIB上关闭AutoLayout,那么异常也会停止抛出。但是顶级元素的布局是错误的,并且框的大小不正确。这不是那么复杂,以至于我无法手动完全解决这个问题。

奇怪的是,在我的第一个版本的UI上它没有抛出。第一个版本为顶级视图和所有子视图设置了Autolayout。

我不能为我的生活找到一个晦涩的设置,而不是另一个。我粘贴了在窗口版本中工作的完全相同的代码,用于将视图交换到基于文档的版本中,然后我通过控制检查每个设置来控制。

我第一次解决这个问题的记忆是我在XIB上关闭了AutoLayout,但现在看着它试图第二次修复,AutoLayout已经打开并且工作正常。

第一个版本有效 - 第二个版本没有。我唯一能想到的是NSDocument中的某些东西或其他东西导致了这个问题。

但是我确实找到了解决第二种情况的方法:关闭用作视图容器的NSBox的“AutoResizes子视图”复选框。

为什么UI的第一个版本不需要这个(对于那个复选框设置可以正常工作)是个谜。

无论如何 - 在此处记录,以防它帮助其他人。