NSLayoutConstraint "UIView-Encapsulated-Layout-Height"とは何ですか?強制的にクリーンに再計算するにはどうすればよいですか?


262

UITableViewiOS 8で実行していて、ストーリーボードの制約からセルの自動高さを使用しています。

自分のセルの1つにシングルが含まれていて、UITextViewユーザー入力に基づいて縮小および拡張する必要があります-テキストを縮小/拡張するにはタップします。

これを行うには、テキストビューにランタイム制約を追加し、ユーザーイベントに応じて制約の定数を変更します。

-(void)collapse:(BOOL)collapse; {

    _collapsed = collapse;

    if(collapse)
        [_collapsedtextHeightConstraint setConstant: kCollapsedHeight]; // 70.0
    else
        [_collapsedtextHeightConstraint setConstant: [self idealCellHeightToShowFullText]];

    [self setNeedsUpdateConstraints];

}

これを行うときはいつでも、tableView更新でラップして呼び出します[tableView setNeedsUpdateConstraints]

[tableView beginUpdates];

[_briefCell collapse:!_showFullBriefText];

[tableView setNeedsUpdateConstraints];
// I have also tried 
// [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
// with exactly the same results.

[tableView endUpdates];

これを行うと、セルが展開します(そして、展開中にアニメーション化します)が、制約の警告が表示されます。

2014-07-31 13:29:51.792 OneFlatEarth[5505:730175] 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) 

(

    "<NSLayoutConstraint:0x7f94dced2b60 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...'(388)]>",

    "<NSLayoutConstraint:0x7f94dced2260 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...']-(15)-|   (Names: '|':UITableViewCellContentView:0x7f94de5773a0 )>",

    "<NSLayoutConstraint:0x7f94dced2350 V:|-(6)-[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...']   (Names: '|':UITableViewCellContentView:0x7f94de5773a0 )>",

    "<NSLayoutConstraint:0x7f94dced6480 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7f94de5773a0(91)]>"
 )

Will attempt to recover by breaking constraint 

<NSLayoutConstraint:0x7f94dced2b60 V:[UITextView:0x7f94d9b2b200'Brief text: Lorem Ipsum i...'(388)]>

388は計算された高さです。その他の制約は、UITextViewXcode / IBによるものです。

最後の問題は私を悩ませています- UIView-Encapsulated-Layout-Heightそれは最初にレンダリングされたときのセルの計算されたUITextView高さだと思います-(私は高さを70.0以上に設定しました)しかし、この派生制約がユーザーcnstraintを更新しました。

さらに悪いことに、レイアウトコードは高さの制約を破ろうとしていると示していますが、そうではありません。セルの高さを再計算し、すべてが希望どおりに描画されます。

それで、NSLayoutConstraint UIView-Encapsulated-Layout-Height(私はそれが自動セルサイジングのために計算された高さだと思います)とは何ですか、そしてそれをきれいに再計算するよう強制するにはどうすればよいですか?


3
Apple 開発
Rog

3
同様の問題を次の方法で解決しましたが、iOS 7/8で動作します。1)制約優先順位の1つを750に下げます。1番目または2番目を試します。2)awakeFromNibセットのセルサブクラスでself.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;。最初に自動サイズ変更マスクを設定すると、最後の制約が追加されなくなると思います。:私はここに、このソリューション見つけgithub.com/wordpress-mobile/WordPress-iOS/commit/...
ジェシー

3
@RogerNolan、何かニュース?Interface BuilderでAuto-layoutをプレイしているときに同じ問題が見つかりました。一部のセルはこの問題を引き起こし、一部はそうではありません。
orkenstein 2014年

3
自動サイズ変更マークを追加することは良い解決策だとは思いません。
Rog

1
@RogerNolanこれらのレイアウト変更を実行する前に、IBでこのセルを生成していますか?私は同じ問題をデバッグしてきましたが、余分な制約を追加していませんでした。私は自分のビューを最初から再構築して警告を抑制できました。2つのストーリーボードファイルを比較したときの唯一の違いは、警告のあるバージョンの<rect key="frame" x="0.0" y="0.0" width="600" height="110"/>定義に行が欠けていたことで、これはIBのバグであると思いました。。とにかく少なくとも私のものでした。
Ell Neal

回答:


301

の優先度_collapsedtextHeightConstraintを999 に下げてみてください。そのようにして、システムはUIView-Encapsulated-Layout-Height制約が常に優先ます。

それはあなたが何を返すかに基づいています -tableView:heightForRowAtIndexPath:。正しい値と独自の制約を返すようにしてください。生成されたものは同じでなければなりません。折りたたみ/展開アニメーションの実行中の競合を回避するために、独自の制約の優先度を低くする必要があるのは、一時的にのみです。


74
それは私が望むものの正反対を達成します。UIView-Encapsulated-Layout-Heightが間違っています-前のレイアウトに属しています。
Rog

7
UIView-Encapsulated-Layout-Height高さが決定されると制約はのUITableViewによって追加されます。systemLayoutSizeFittingSizecontentView の高さに基づいて高さを計算します。ここでは、関係ありUIView-Encapsulated-Layout-Heightません。次に、tableViewはcontentSizeをによって返される値に明示的に設定しheightForRowAtIndexPath:ます。この場合、rowHeightsが計算された後にtableView制約が優先される必要があるため、カスタム制約の優先度を下げることが適切です。
Ortwin Gentz

8
@OrtwinGentz:rowHeightsの計算後にtableView制約を優先する必要があるため、カスタム制約の優先度を下げることが正しいとは言えません。UIView-Encapsulated-Layout-Height優先度を下げないと問題が発生します...
テスト

38
私はそれが実際の問題を修正しない衝突を回避していると私は主張します-これはまだAppleのバグのように感じるので、それはおそらく正しいことだと思います。特にAppleがこの制約を再計算し、エラーが出力された後にすべてが正しくレイアウトされるという事実に照らして。
Rog

9
追加されている制約が正しいと想定しているため、この回答の場合は-1。UIView-Encapsulated-Layout-Width私の場合に追加されたものは間違っていますが、実行時の明示的な制約よりも優先されるようです。
光線

68

同様のシナリオがあります。UILabelオブジェクトの行が数行ある、1行のセルを持つテーブルビューです。iOS 8と自動レイアウトを使用しています。

回転すると、システムで計算された行の高さが間違っていました(43.5は実際の高さよりもはるかに低いです)。それは次のようになります:

"<NSLayoutConstraint:0x7bc2b2c0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7bc37f30(43.5)]>"

それは単なる警告ではありません。テーブルビューセルのレイアウトがひどい-すべてのテキストが1つのテキスト行に重なっています。

次の行が私の問題を魔法のように「修正」していることに驚かされます(autolayoutは何も文句を言わず、画面上に期待どおりの結果が得られます)。

myTableView.estimatedRowHeight = 2.0; // any number but 2.0 is the smallest one that works

この行の有無にかかわらず:

myTableView.rowHeight = UITableViewAutomaticDimension; // by itself this line only doesn't help fix my specific problem

8
最後に!これが正解です。WWDCセッションで、行の高さの自動サイズ設定を使用する場合は、estimatedRowHeightを設定する必要があります。そうしないと、問題が発生します。(はい、アップルは本当に厄介なことが起こりました)
Abdalrahman Shatou 2015年

50
FWIW、見積もりを追加しても、私にはまったく違いがありませんでした。
ベンジョン

3
へえ。私は再びこの同じ答えに戻り、喜びと希望を持ってそれを実行しに行きました。繰り返しになりますが、私には違いはありません:-)
Benjohn

3
tableView:estimatedHeightForRowAtIndexPath:によって返される推定値は、少なくともセルと同じ大きさでなければなりません。そうしないと、テーブルの計算された高さが実際の高さより低くなり、テーブルが上にスクロールする場合があります(たとえば、アンセグエがテーブルに戻った後など)。UITableViewAutomaticDimensionは使用しないでください。
Matt

1
低いほど、最初に呼び出されるestimatedRowHeight頻度cellForRowAtIndexPathが高くなることに注意してください。正確には、tableviewの高さを見積もられたRowHeight時間で割った値。12インチのiPad Proでは、これは数千に及ぶ可能性があり、データソースを破壊し、大幅な遅延を引き起こす可能性があります。
Mojo66 2016

32

警告メッセージがそれを破らなければならないと言っている制約の値の1つに優先度を指定することにより、警告を消すことができました(以下"Will attempt to recover by breaking constraint")。私は優先順位を何かよりも大きいものに設定している限り、49、警告は表示さです。

私にとってこれは私の制約を変更することを意味し、警告はそれが壊れようとしたと言った:

@"V:|[contentLabel]-[quoteeLabel]|"

に:

@"V:|-0@500-[contentLabel]-[quoteeLabel]|"

実際、その制約の任意の要素に優先順位を付けることができ、それが機能します。どちらでもかまいません。細胞が適切な高さになり、警告が表示されません。ロジャー、たとえば、高さの値の制約の@500直後に追加してみてください388(例388@500

これが機能する理由は完全にはわかりませんが、少し調査しました。でNSLayoutPriority列挙、と思われるNSLayoutPriorityFittingSizeCompression優先順位があります50。その優先度レベルのドキュメントには次のように書かれています:

FittingSizeメッセージをビューに送信すると、ビューのコンテンツに十分な大きさの最小サイズが計算されます。これは、その計算でビューをできるだけ小さくしたい優先度レベルです。かなり低いです。一般に、まさにこの優先順位で制約を作成することは適切ではありません。あなたはより高くまたはより低くなりたいです。

参照されたメッセージのドキュメントfittingSize次のとおりです。

保持する制約を満たすビューの最小サイズ。(読み取り専用)

AppKitは、このプロパティを、ビューとそのサブビューが保持するすべての制約を考慮し、ビューを可能な限り小さくするための設定を満たしていることを考慮して、ビューに使用できる最適なサイズに設定します。このプロパティのサイズ値が負になることはありません。

私はそれ以上掘り下げていませんが、これが問題のある場所と関係があることは理にかなっているようです。


サックスジェフ。それでも私にはバグのように感じます。Appleはrdarに応答しませんでした:-(
Rog

13

99.9%の確率で、カスタムセルまたはヘッダーを使用しているUITableViewsときに、テーブルの初回ロード時にすべての競合が発生します。ロードすると、通常は再び競合が発生することはありません。

これは、ほとんどの開発者が通常、固定された高さまたはアンカー制約を使用してセル/ヘッダー内の要素をレイアウトするために発生します。UITableView最初のロード/レイアウト時に、セルの高さが0に設定されるため、競合が発生します。これは、独自の制約と明らかに競合します。これを解決するには、固定の高さの制約を低い優先度に設定するだけです(.defaultHigh)。コンソールメッセージを注意深く読んで、レイアウトシステムがどの制約に違反すると決定したかを確認してください。通常、これは優先順位を変更する必要があるものです。次のように優先度を変更できます。

let companyNameTopConstraint = companyNameLabel.topAnchor.constraint(equalTo: companyImageView.bottomAnchor, constant: 15)
    companyNameTopConstraint.priority = .defaultHigh

NSLayoutConstraint.activate([
            companyNameTopConstraint,
           the rest of your constraints here
            ])

1
美しい説明。
グレン

12

私の方法cell.layoutIfNeeded()にあった偽物を取り除くことで、このエラーを解決することができました。tableViewcellForRowAt


1
はい、これで問題が解決しました。私はコードレイアウトの制約を行っていたので、最初は何かを見落とす可能性があると思いました。ありがとう
ジョン

1
同じこと!ありがとう!
Andrey Chernukha

7

制約を更新するようにテーブルビューに通知する代わりに、セルをリロードしてみてください。

[tableView beginUpdates];

[_briefCell collapse:!_showFullBriefText];

[tableView reloadRowsAtIndexPaths:@[[tableView indexPathForCell:_briefCell]] withRowAnimation:UITableViewRowAnimationNone];

[tableView endUpdates];

UIView-Encapsulated-Layout-Height おそらく、そのときのセルの制約に基づいて、初期ロード中にセルに対して計算されたテーブルビューの高さです。


私は私の質問で述べるべきだったのですが、これを試してみましたが機能しません。UIView-Encapsulated-Layout-Heightについてのあなたの推測に同意します
Rog

6
とにかく、少なくとも答えを提出するための賞金を持っています。SOはそうでなければ蒸発させるだけのようです。
Rog、2013

6

別の可能性:

自動レイアウトを使用してセルの高さ(contentViewの高さ、ほとんどの場合は以下のとおり)を計算し、uitableviewセパレーターがある場合は、セルの高さを返すために、セパレーターの高さを追加する必要があります。正しい高さを取得すると、その自動レイアウト警告は表示されなくなります。

- (CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell {
   [sizingCell setNeedsLayout];
   [sizingCell layoutIfNeeded];
   CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
   return size.height; // should + 1 here if my uitableviewseparatorstyle is not none

}

一部のシミュレーター(iPad 6 Plus)でのみかなり複雑なセルレイアウトのレイアウト高さのあいまいさを取得した場合、それは私を助けました。いくつかの内部丸めエラーのため、コンテンツが少し圧迫されているように見え、制約を圧迫する準備ができていない場合は、あいまいになります。だから私は戻るのUITableViewAutomaticDimensionheightForRowAtIndexPathはなく、私は戻る [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize] + 0.1
レオ

もちろんです[sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height + 0.1
レオは

驚異的に; セパレーターを削除すると、テーブルが正常に動作します。ありがとうございます。
ロイヤルマーダー

5

で述べたようにジェシー質問のコメントで、これは私のために動作します:

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;

ちなみに、この問題はiOS 10では発生しません。


2
Swift 4.2では、self.contentView.autoresizingMask = [.flexibleHeight]
airowe

4

UITableViewAutomaticDimensionを使用してセル内のビューの高さの制約を変更すると、このエラーが発生しました。

最後に、制約定数値が最も近い整数に切り上げられていないことが原因であることがわかりました。

let neededHeight = width / ratio // This is a CGFloat like 133.2353
constraintPictureHeight.constant = neededHeight // Causes constraint error
constraintPictureHeight.constant = ceil(neededHeight) // All good!

2
これが私の問題の原因となったコメントでした。動的にロード(拡大および縮小)するイメージセルと、estimatedRowHeight = 50およびrowHeight = UITableViewAutomaticDimensionのテーブルビューがあります。テーブルビューが正しい高さであったにもかかわらず、私はまだ制約を破っていました。セパレーターの高さが0.3333であることがわかりました。それが、セル内の画像サイズの制約を壊していたのです。セパレーターをオフにした後、すべてが順調でした。何を探すべきか教えてくれてチェに感謝します。
migs647

1
この場合、追加の制約を作成します(例:bottomMargin> = view.bottomMargin+1@900)。AutoLayoutは余分な1ポイントに対応しようとし、セルのサイズを変更し、セパレーターの高さのために混乱し、いくつかの制約を解除または緩和しようとし、@ 900を見つけてそれを破棄します。あなたは警告なしであなたが望むレイアウトを得ます。
アントン

私の日を保存します。とにかく数時間
アントントロパシュコ

1

コンテンツに合わせてテキストビューのサイズを変更し、高さの制約定数を結果の高さに更新して、UIView-Encapsulated-Layout-Height制約の矛盾を修正しました。例:

[self.textView sizeToFit];
self.textViewHeightConstraint.constant = self.textView.frame.size.height;

どこでやったの?layoutSubviews?
stuckj 2016年

1

このバグで頭を悩ませて数時間過ごした後、ようやく私に役立つ解決策を見つけました。私の主な問題は、さまざまなセルタイプに対して複数のペン先を登録していたが、1つのセルタイプが異なるサイズを持つことが許可されていたことでした(そのセルのすべてのインスタンスが同じサイズになるわけではありません)。そのため、テーブルビューがそのタイプのセルをデキューしようとしていて、たまたま高さが異なる場合に問題が発生しました。設定で解決しました

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; self.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});

セルがそのサイズを計算するためのデータを持っているときはいつでも。私はそれができると思います

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

何かのようなもの

cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight; cell.frame = CGRectMake(0, 0, self.frame.size.width, {correct height});

お役に立てれば!


0

TableViewは、デリゲートからindexPathのセルの高さを取得します。次にからセルを取得しますcellForRowAtIndexPathます:

top (10@1000)
    cell
bottom (0@1000)

cell.contentView.height:0 // <->(UIView-Encapsulated-Layout-Height:0 @ 1000)top(10 @ 1000)が(UIView-Encapsulated-Layout-Height:0 @ 1000)と競合する場合、

優先度は1000であるためですUIView-Encapsulated-Layout-Height。優先度の下に最優先を設定する必要があります。


0

次のようなメッセージが表示されました。

制約を同時に満たすことができません...
...
...
...
NSLayoutConstraint:0x7fe74bdf7e50 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7fe75330c5c0(21.5)]
...
...
によって回復を試みます制約違反NSLayoutConstraint:0x7fe0f9b200c0 UITableViewCellContentView:0x7fe0f9b1e090.bottomMargin == UILabel:0x7fe0f9b1e970.bottom

身長にカスタムUITableViewCellを使っていますUITableViewAutomaticDimension。また、estimatedHeightForRowAtIndex:メソッドも実装しました。

問題を引き起こしていた制約はこのようなものでした

[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[title]-|" options:0 metrics:nil views:views];

制約をこれに変更すると問題が解決しますが、別の回答と同様に、必要な制約の優先度が低くなるため、これは正しくないと感じました。

[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-6@999-[title]-6@999-|" options:0 metrics:nil views:views];

ただし、気付いたのは、実際に優先度を削除しただけでも機能し、制約違反のログが取得されないことです。

[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-6-[title]-6-|" options:0 metrics:nil views:views];

これは、|-6-[title]-6-|との違いについて少し謎|-[title-|です。しかし、サイズを指定することは私にとって問題ではなく、ログを取り除くので、必要な制約の優先度を下げる必要はありません。


0

これview.translatesAutoresizingMaskIntoConstraints = NO;を設定すると、この問題が解決されます。


これは完璧な解決策ではなかったとしても、私にとっては完璧に機能しました。
Enkha

0

コレクションビューセルでも同様の問題がありました。

セルの下部にリンクされた最終的な制約の優先順位(ビューの上部から下部へのチェーンの最後の制約-これが最終的に高さを決定するものです)を999に下げることで解決しました。

セルの高さは正しく、警告は消えました。

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