web-dev-qa-db-ja.com

UITableViewCellのAutoLayoutに関する問題

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ポイントを示します。これは、プロトタイプが大まかに配置されている場所です(プロトタイプ内で移動すると、デバッグコンソールで制約の変更が表示されます)が、これは、イメージビューとラベル間の「標準」距離の独自の制約と競合します。 。

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

33
Stephen Moore

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

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

    この問題を修正するには、Interface Builderで必要な最小限の制約を追加して、各ビューの位置とサイズを完全に指定し、次にこれらの不要な制約をそれぞれ選択して、右側のサイドバーの属性インスペクターに移動し、Placeholder-ビルド時に削除します

    Screenshot of the constraint Placeholder checkbox in Xcode 6.

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

    プレースホルダー制約とアンインストールされた制約の違いは何ですか?ここに私のスライドがあります Adaptive Auto Layoutトーク(ビデオ)PDFスライド )2つの比較:

    Comparison between Placeholder constraints and Uninstalled constraints.

  2. updateConstraintsでは、制約を削除して、既存のように再度追加する必要はありません。何故なの?基本的に、パフォーマンスはひどいです。Appleエンジニアはこれは良いアイデアではないことを確認しました。ここに投稿した 質問/回答 を参照してください)詳細、およびこれ answer 。制約が2回以上追加されるのを防ぐために、ブールフラグ(たとえば、hasSetupConstraints)を使用します。初めて制約を追加し、updateConstraintsが再度呼び出された場合、追加する新しい制約がない場合はすぐに戻ることができます。詳細については、 この質問 を参照してください。

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

79
smileyborg