web-dev-qa-db-ja.com

自動レイアウトでサブビューの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>>
79
Patrick Perini

エラーの状態に応じて、制約に関係するビューが追加するビューまたはそのビューのサブビューになるように、ビューに制約を追加する必要があります。上記のコードの場合、その制約を[self internalView]ではなくselfに追加する必要があります。書かれているとおりに動作しない理由は、制約に関係するビューの1つである([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]];
92
Charles A.

ここに来る他の人のために:階層にサブビューを追加する前に制約を追加したため、このエラーが発生しました。

115

短い答えスワップ親と子のビュー。
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)]];
36
SwiftArchitect

追加のヒント:

IOS7では正常に動作するが、iOS8では「ビュー階層が制約に対応していません」というエラーが発生する、新しく開発されたアプリがあります。

他の投稿を読んで、制約を作成する前に(サブ)ビューを追加する必要があると述べました。私はそれをしましたが、それでもエラーが発生しました。

その後、viewDidLoadではなく-(void)viewDidAppearの下に制約を作成する必要があることがわかりました

10
Kevin

これは古い質問ですが、ドキュメントから次の行を指摘します。

IOS 8.0以降向けに開発する場合、addConstraint(_ :)メソッドを直接呼び出す代わりに、制約のisActiveプロパティをtrueに設定します。 isActiveプロパティは、正しいビューから自動的に制約を追加および削除します。

少なくとも、間違ったビューでaddConstraintを呼び出すことを心配する必要がなくなるため、これにより1つの障害点が削除されます。

5
WongWray

私の場合、現在作成されているビューの代わりにルートビューを制約のコンテナとして使用することで解決しました。

つまり、viewController内で使用します

imageView.addConstraints...の代わりにview.addConstraints([leftConstraintImage, topConstraintImage])

2
Vyacheslav

@CharlesAが彼の答えで指摘しているように、問題は追加するビューが適切なビュー階層にないことです。彼の答えは良いものですが、私にとってこの問題を引き起こした特定のユースケースについて詳細に説明します。

instantiateViewControllerWithIdentifierを使用してインスタンス化したView Controllerのビューに制約を追加しようとしたときに、この問題が発生しました。この問題を解決するために、[childViewController didMoveToParentViewController:self]を使用しました。これにより、制約によって参照されるビュー階層にビューが追加されました。

1
benvolioT