33

プロジェクトの自動レイアウトに問題がありxcode 5ます。内部でナビゲーションコントローラーを備えたプレーンビューコントローラーを使用しています。MKMapView上半分と下半分にがUITableViewあります。を使用しstoryboardsて、プロトタイプを構成しましたUITableViewCellが、コードを使用して制約を追加しています。プロトタイプのすべてのコントロールを再確認しましたが、そこに構成されている制約はありません。の制約を追加すると、問題が発生しますUITableViewCell。セルに次のコードがあります。

-(void)updateConstraints {
    [super updateConstraints];
    //first remove old constraints
    [self removeConstraints:self.constraints];
    [self.nameLabel removeConstraints:self.nameLabel.constraints];
    [self.addressLabel removeConstraints:self.nameLabel.constraints];
    [self.rentableSquareFeetLabel removeConstraints:self.rentableSquareFeetLabel.constraints];
    [self.lastSaleAmountLabel removeConstraints:self.lastSaleAmountLabel.constraints];
    [self.lastSaleDateLabel removeConstraints:self.lastSaleAmountLabel.constraints];
    [self.thumbnailImageView removeConstraints:self.thumbnailImageView.constraints];

    //then set up constraints
    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(_thumbnailImageView, _nameLabel, _rentableSquareFeetLabel, _lastSaleAmountLabel, _addressLabel, _lastSaleDateLabel);
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_thumbnailImageView(60)]-[_nameLabel(<=200)]-(>=8)-[_rentableSquareFeetLabel]-(>=8)-[_lastSaleAmountLabel]|" options:0 metrics:nil views:viewsDictionary]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_nameLabel]-(-4)-[_addressLabel]" options:NSLayoutFormatAlignAllLeading metrics:nil views:viewsDictionary]];
    [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_lastSaleAmountLabel]-(-4)-[_lastSaleDateLabel]" options:NSLayoutFormatAlignAllLeading metrics:nil views:viewsDictionary]];
}

デバッグコンソールで次のようになっています。例外は、最初の addConstraints 行によってトリガーされます。これらを続行すると、xcodeが正しい制約を破ることを選択しているように見えるため、最終的にすべてが本来あるべき姿で表示されます。

2013-09-25 15:07:14.169 PECProperties[32381:a0b] Unable to simultaneously satisfy constraints.  Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)  (
    "<NSIBPrototypingLayoutConstraint:0x9d56c70 'IB auto generated at build time for view with fixed frame' H:|-(0)-[UIImageView:0x9d558f0](LTR)   (Names: '|':UITableViewCellContentView:0x9d55620 )>",
    "<NSIBPrototypingLayoutConstraint:0x9d56d20 'IB auto generated at build time for view with fixed frame' H:[UIImageView:0x9d558f0(60)]>",
    "<NSIBPrototypingLayoutConstraint:0x9d56d80 'IB auto generated at build time for view with fixed frame' H:|-(78)-[UILabel:0x9d559e0](LTR)   (Names: '|':UITableViewCellContentView:0x9d55620 )>",
    "<NSLayoutConstraint:0x9d53830 H:[UIImageView:0x9d558f0]-(NSSpace(8))-[UILabel:0x9d559e0]>" )

Will attempt to recover by breaking constraint  <NSIBPrototypingLayoutConstraint:0x9d56d80 'IB auto generated at build time for view with fixed frame' H:|-(78)-[UILabel:0x9d559e0](LTR)   (Names: '|':UITableViewCellContentView:0x9d55620 )>

Break on objc_exception_throw to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

3 番目の NSIBPrototypingLayoutConstraint は、ビューの端とラベルの間に 78 のポイントを示しています。それはプロトタイプが大まかに配置されている場所です(プロトタイプで移動すると、デバッグコンソールで制約の変更が表示されます)が、画像ビューとラベルの間の「標準」距離の独自の制約と競合します.

translatesAutoresizingMaskIntoConstraints=NOビューコントローラーの で を 設定しようとしましたcellForRowAtIndexPathが、それも役に立たないようです。レイアウトを修正するにはどうすればよいですか?

4

1 に答える 1

79

ここでカバーするいくつかのこと:

  1. 実行している (そして例外を引き起こしている)NSIBPrototypingLayoutConstraint制約は、Storyboard または XIB ビューのレイアウトを明確にするために、Interface Builder によって自動生成されます。これを行うのはかなり卑劣ですが、あいまいな各ビューの位置とサイズが完全に指定されるように、必要な最小限の制約が自動的に追加されます。これは Xcode 4 からの変更点です。Xcode 4 では、Interface Builder であいまいなレイアウトを使用できなかったためです。Xcode 5 以降では可能ですが、コンパイル時にレイアウトがあいまいな場合、IB はこれらの制約を自動生成します。

    この問題を修正する方法は、Interface Builder で最低限必要な制約を追加して、各ビューの位置とサイズが完全に指定されるようにし、これらの不要な制約をそれぞれ選択して、右側のサイドバーの [属性] インスペクターに移動し、[プレースホルダー]の横にあるチェックボックスをオンにすることです。 - ビルド時に削除します。

    Xcode 6 の制約プレースホルダー チェックボックスのスクリーンショット。

    このチェックボックスは、追加した制約を削除するだけでなく、最も重要なことに、自動生成された IB 制約が代わりに使用されないようにします! (ご想像のとおり、IB に多数のビューがあり、すべての制約をコードで管理したい場合、これは非常に面倒です。このため、Auto を実装する予定のビュー階層に IB を完全に使用することは避けたい場合があります。プログラムでレイアウトします。)

    Placeholder 制約と Uninstalled 制約の違いは何ですか? 以下は、Adaptive Auto Layout の講演 (ビデオ) ( PDF スライド) のスライドで、この 2 つを比較しています。

    プレースホルダー制約とアンインストール制約の比較。

  2. ではupdateConstraints、制約を削除して、そこにあるように再度追加する必要はありません。なぜだめですか?基本的に、これはパフォーマンスにとってひどいものであり、これは良い考えではないことを Apple のエンジニアに確認しました。詳細については、ここに投稿した質問/回答と、この回答を参照してください。制約が複数回追加されるのを防ぐためにhasSetupConstraints、最初に制約を設定した後に YES に設定するブール値フラグ (例: ) を使用します。updateConstraints再度呼び出された場合、新しい制約がない場合はすぐに戻ることができます。たす。詳細については、この質問を参照してください。

  3. 制約を削除するために使用しているコードは、完全には機能しない可能性があります。これは、[view removeConstraints:view.constraints]が追加された制約のみを削除するためです。view制約は、それらが制約するビューの共通のスーパービューに追加できることに注意してください。また、追加された制約viewだけが のレイアウトに影響を与えるとは限りませんview。多数の制約を削除する必要がある場合は、それらの各制約への参照をプロパティ (NSLayoutConstraint インスタンスを含む NSArray プロパティなど) に保存し、NSLayoutConstraint の API またはPureLayout open-ソース ライブラリ. 計算コストが高くなるため、非アクティブ化/削除する制約はできるだけ少なくする必要があります。一方、constant制約の を変更することは非常に効率的であり、推奨されます。そのために制約を削除したり、再度追加したりする必要はありません。

于 2013-09-26T05:24:31.977 に答える