在自动布局中将子视图的X居中会引发“未为约束做准备”


82

我有一个自定义的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>>

Answers:


95

作为错误状态,您必须将约束添加到视图,以使约束中涉及的视图是您要添加到该视图的视图或该视图的子视图。对于上面的代码,您应该将该约束添加到self,而不是添加[self internalView]。它不能按书面形式工作的原因是约束(self)中涉及的视图之一不在视图层次结构中(如果您仅考虑[self internalView]以下内容)。

有关详细信息,请参阅该文档的讨论部分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]];

那给了我一个错误要求Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want.,然后它就中断了<NSLayoutConstraint:0x126ad4c0 UIView:0xadd2e20.centerX == MyView:0xadd19b0.centerX>
Patrick Perini

1
最有可能的原因是您没有禁用将自动调整大小的蒙版转换为约束的功能。我将在上面更新我的代码。您可能还需要添加宽度/高度约束以使其可见,并且我建议在中心Y上添加约束或对自身进行某种顶部/底部约束,以使布局定义得当。
Charles A.

所以你不能有类似的布局:@"V:|[v]|"?因为这将是一个超级视图?
2013年

1
@Sam这是一个有效的约束,但不会使所表示的视图居中[v],它将为您提供标准大小的[v]上下边界及其上下视图之间的上下约束。我相信,您还必须将其添加到超级视图中。
Charles A.

8
一个简单的经验法则:与视图大小相关的所有约束都应添加到同一视图中,而与位置相关的任何约束都应添加到其父视图中。
Deepak GM

117

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


谢谢,您节省了我很多时间!
Stas 2013年

这是到目前为止我注意到的最常见的失败原因。
Ayan Sengupta

确切地说,当您这样做时,constraintWithItem: youView其中不存在该项目!
纳齐尔

36

简短答案交换父子视图。
假设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]))

对象


10

其他提示:

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

阅读其他文章说,在创建约束之前需要添加(sub)views。我做到了,但仍然出现错误。

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


2
viewDidAppear()被调用时,认为已经是对用户可见。如果要修改约束,则应在之前viewWillLayoutSubviews()。更多生命周期在这里:medium.com/@SergiGracia/...
maganap

6

这是一个老问题,但我想从文档中指出这一行:

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

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


2

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

我的意思是,在viewController内部使用

view.addConstraints([leftConstraintImage, topConstraintImage]) 代替 imageView.addConstraints...


1

正如@CharlesA在他的答案中指出的那样,问题是您要添加的视图不在正确的视图层次结构中。他的答案是一个很好的答案,但是我将针对导致我这个问题的特定用例进行详细介绍:

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


0

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

addSubview(yourSubViewHere)
yourSubViewHere.translatesAutoresizingMaskIntoConstraints = false

addConstraint(NSLayoutConstraint(....
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.