サブビューの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>>

回答:


95

エラーが示すように、制約に関係するビューが、それを追加するビューまたはそのビューのサブビューになるように、ビューに制約を追加する必要があります。上記のコードの場合、その制約を。selfではなく、に追加する必要があります[self internalView]。記述どおりに機能しない理由は、制約(self)に含まれるビューの1つが、[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 2013

1
自動サイズ変更マスクの制約への変換を無効にしなかったことが原因である可能性があります。上記のコードを更新して、そうします。表示するには、幅/高さの制約も追加する必要があります。レイアウトを明確に定義するには、中央のYに制約を追加するか、ある種の上部/下部の制約を自分自身に追加することをお勧めします。
Charles A.

したがって、次のようなレイアウトを使用することはできません@"V:|[v]|"。これはスーパービューを指すので?
サム

1
@Samこれは有効な制約ですが[v]、で表されるビューを中央に配置しません。これにより、[v]の上端と下端の間の標準サイズとそのスーパービューの上下の制約が与えられます。また、それをスーパービューに追加する必要があると思います。
Charles A.

8
簡単な経験則:ビューのサイズに関連する制約はすべて同じビューに追加し、その位置に関連する制約はすべてその親に追加する必要があります。
Deepak GM

117

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


ありがとう、あなたは私に多くの時間を節約しました!
stas 2016年

これが、私がこれまでに気付いたこの失敗の最も一般的な理由です。
Ayan Sengupta 2016年

正確にそしてあなたがそれをconstraintWithItem: youViewするとき、アイテムはそれに存在しません!
ナジル2016年

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]))

Obj-C


10

追加のヒント:

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

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

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


2
ときviewDidAppear()に呼び出され、ビューがすでにユーザーに表示されます。制約を変更する場合は、その前に、で行う必要がありますviewWillLayoutSubviews()。もっとここにライフサイクルの:medium.com/@SergiGracia/...
maganap

6

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

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

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


2

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

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

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


1

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

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


0

最初にサブビューを追加してから、次のように制約を追加します

addSubview(yourSubViewHere)
yourSubViewHere.translatesAutoresizingMaskIntoConstraints = false

addConstraint(NSLayoutConstraint(....
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.