在自动布局中将子视图的 X 居中会抛出“没有为约束做好准备”

我有一个自定义的 UIView 子类,它正在通过一个笔尖进行初始化。

-awakeFromNib中,我正在创建一个子视图,并试图将它放在其子视图的中心。

[self setInteralView: [[UIView alloc] init]];
[[self internalView] addConstraint: [NSLayoutConstraint constraintWithItem: [self internalView]
attribute: NSLayoutAttributeCenterX
relatedBy: NSLayoutRelationEqual
toItem: self
attribute: NSLayoutAttributeCenterX
multiplier: 1
constant: 0]];

这会中断,并导致以下输出:

2013-08-11 17:58:29.628 MyApp[32414:a0b] The view hierarchy is not prepared for the constraint: <NSLayoutConstraint:0xc1dcc80 UIView:0xc132a40.centerX == MyView:0xc1315a0.centerX>
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
2013-08-11 17:58:29.630 MyApp[32414:a0b] View hierarchy unprepared for constraint.
Constraint: <NSLayoutConstraint:0xc1dcc80 UIView:0xc132a40.centerX == MyView:0xc1315a0.centerX>
Container hierarchy:
<UIView: 0xc132a40; frame = (0 0; 0 0); clipsToBounds = YES; layer = <CALayer: 0xc132bc0>>
View not found in container hierarchy: <MyView: 0xc1315a0; frame = (-128 -118; 576 804); layer = <CALayer: 0xc131710>>
That view's superview: <UIView: 0xc131a70; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0xc131b50>>
53979 次浏览

如错误所述,必须将约束添加到视图中,以便约束中涉及的视图是要将其添加到的视图或该视图的子视图。对于上面的代码,您应该将该约束添加到 self,而不是 [self internalView]。它之所以不能按照编写的方式工作,是因为如果只考虑 [self internalView]或更低版本,那么约束中涉及的视图之一(self)不在视图层次结构中。

有关更多细节,请参见 addConstraint:方法上的 文件的讨论部分

这是您的代码行,按照我的建议固定:

UIView* internalView = [[UIView alloc] initWithFrame:CGRectZero];
internalView.translatesAutoresizingMaskIntoConstraints = NO;
[self setInternalView:internalView];


[self addConstraint: [NSLayoutConstraint constraintWithItem: [self internalMapView]
attribute: NSLayoutAttributeCenterX
relatedBy: NSLayoutRelationEqual
toItem: self
attribute: NSLayoutAttributeCenterX
multiplier: 1
constant: 0]];

正如@CharlesA 在他的回答中指出的那样,问题在于您要添加的视图不在正确的视图层次结构中。他的回答很好,但是我要为一个特定的用例提供一些细节,正是这个用例导致了我的这个问题:

当我试图向一个视图添加约束时发生了这种情况,我已经使用 instantiateViewControllerWithIdentifier实例化了该视图的视图控制器。为了解决这个问题,我使用了 [childViewController didMoveToParentViewController:self]。这将视图添加到由我的约束引用的视图层次结构中。

对于来到这里的其他人: 我得到了这个错误,因为我在将子视图添加到层次结构之前添加了约束。

附加提示:

我有一个新开发的应用程序在 iOS7上运行良好,但在 iOS8上出现错误“视图层次结构没有为约束做好准备”。

阅读一些其他文章说,(子)视图需要添加之前创建约束。我那样做了,但仍然得到了错误。

然后我发现我应该在-(void) viewDidAppear 而不是 viewDidLoad 下创建约束

简短回答 : 交换父子视图。
假设 self是母视图:

  • : [subview addConstraint [NSLayoutConstraint constraintWithItem:self...

  • : [self addConstraint [NSLayoutConstraint constraintWithItem:subview...


斯威夫特

subview.translatesAutoresizingMaskIntoConstraints = false
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
"H:|-0-[subview]-0-|",
options: .DirectionLeadingToTrailing,
metrics: nil,
views: ["subview":subview]))

Obj-C

[subview setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"H:|-0-[subview]-0-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(subview)]];

这是一个古老的问题,但我想从文档中指出这句话:

在为 iOS 8.0或更高版本开发时,将约束的 isActive 属性设置为 true,而不是直接调用 addConstraint (_:)方法。IsActive 属性自动从正确的视图中添加和移除约束。

至少,这将消除一个故障点,因为您不再需要担心在错误的视图上调用 addConstraint

在我的例子中,它是通过使用根视图作为约束的容器而不是当前创建的视图来解决的。

我的意思是,使用内部视图控制器

view.addConstraints([leftConstraintImage, topConstraintImage]) 而不是 imageView.addConstraints...

首先添加 subView,然后像这样添加约束

addSubview(yourSubViewHere)
yourSubViewHere.translatesAutoresizingMaskIntoConstraints = false


addConstraint(NSLayoutConstraint(....