私はiOS 8でUITableView
を実行しています。ストーリーボードの制約からセルの高さを自動調整しています。
私のセルの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は私が計算した高さです、UITextView
に対する他の制約はXcode/IBによるものです。
最後のものは私を悩ませています - 私はUIView-Encapsulated-Layout-Height
が最初にレンダリングされたときのセルの計算された高さであると思います - (私のUITextView
の高さを> = 70.0に設定します)更新されたユーザー制約を無効にします。
さらに悪いことに、レイアウトコードには高さの制約を壊そうとしていると書かれていますが、そうではありません。それでも、セルの高さを再計算して、必要に応じてすべて描画します。
それで、NSLayoutConstraint
UIView-Encapsulated-Layout-Height
とは何ですか(自動セルサイズ決定の計算された高さであると思います)、そしてそれを強制的に再計算するように強制するにはどうすればいいですか?
_collapsedtextHeightConstraint
の優先順位を999に下げてみてください。そのようにして、システム提供のUIView-Encapsulated-Layout-Height
制約が常に優先されます。
これは-tableView:heightForRowAtIndexPath:
に返された内容に基づいています。正しい値と独自の制約を必ず返すようにしてください。生成されたものも同じでなければなりません。あなた自身の制約に対する低い優先順位は、折りたたみ/展開アニメーションが飛んでいる間に衝突を防ぐために一時的に必要とされるだけです。
私は同じようなシナリオを持っています:1行のセルを持つテーブルビュー、そこにはUILabelオブジェクトが数行あります。私はiOS 8と自動レイアウトを使用しています。
私が回転したとき、私は間違ったシステム計算された列の高さを得ました(43.5は実際の高さよりはるかに小さいです)。それはように見えます:
"<NSLayoutConstraint:0x7bc2b2c0 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7bc37f30(43.5)]>"
それは単なる警告ではありません。私のテーブルビューセルのレイアウトはひどいです - すべてのテキストが1つのテキスト行に重なっている。
次の行が私の問題を魔法のように「修正」していることに驚きます(自動レイアウトは何も不平を言わず、私はスクリーンに期待したものを得ます)
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
警告メッセージに表示されている制約の値の1つに priority を指定して警告を消すことができました("Will attempt to recover by breaking constraint"
の下)。優先順位を49
より大きい値に設定している限り、警告は消えます。
私にとって、これは私の制約を変更することを意味していました。
@"V:|[contentLabel]-[quoteeLabel]|"
に:
@"V:|-0@500-[contentLabel]-[quoteeLabel]|"
実際、私はその制約のどの要素にも優先順位を付けることができ、それはうまくいくでしょう。どちらでも構いません。私の細胞は適切な高さになり、警告は表示されません。 Rogerさん、あなたの例として、@500
の高さの値の制約の直後に388
を追加してみてください(例:388@500
)。
なぜこれが機能するのか完全にはわかりませんが、少し調査しました。 NSLayoutPriority enum では、NSLayoutPriorityFittingSizeCompression
の優先度は50
です。その優先順位に関する文書には、次のように記載されています。
FittingSizeメッセージをビューに送信すると、ビューの内容に十分な大きさの最小サイズが計算されます。これは、ビューがその計算でできるだけ小さくなることを望む優先順位レベルです。かなり低いです。一般にこの優先順位で制約を設定するのは適切ではありません。あなたはより高くまたはより低くなりたいです。
参照されているfittingSize
メッセージの documentation は、次のようになります。
保持している制約を満たすビューの最小サイズ。 (読み取り専用)
AppKitは、このプロパティとそのサブビューが保持するすべての制約を考慮し、ビューをできるだけ小さくするという設定を満たすことを考慮して、このプロパティをビューに使用できる最適なサイズに設定します。このプロパティのサイズの値が負になることはありません。
それ以上掘ったことはありませんが、これが問題のある場所に関係していることは意味があるようです。
tableView
のcellForRowAt
メソッドにある偽のcell.layoutIfNeeded()
を削除することで、このエラーを解決することができました。
制約を更新するようにTable Viewに通知する代わりに、セルを再ロードしてみます。
[tableView beginUpdates];
[_briefCell collapse:!_showFullBriefText];
[tableView reloadRowsAtIndexPaths:@[[tableView indexPathForCell:_briefCell]] withRowAnimation:UITableViewRowAnimationNone];
[tableView endUpdates];
UIView-Encapsulated-Layout-Height
はおそらく、その時点でのセルの制約に基づいて、初期ロード中にテーブルビューがセルに対して計算した高さです。
他の可能性:
自動レイアウトを使用してセルの高さ(contentViewの高さ、以下のような場合が多い)を計算する場合、および適切なビューセパレータがある場合は、セルの高さに戻るためにセパレータの高さを追加する必要があります。正しい高さになると、その自動レイアウト警告は表示されません。
- (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
}
問題のコメントで Jesse で述べたように、これは私のために働きます:
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
ちなみに、この問題はiOS 10では発生しません。
UITableViewAutomaticDimensionを使用してセル内のビューの高さの制限を変更すると、このエラーが発生しました。
私は最後に、制約定数値が最も近い整数に切り上げられていないためであると考えました。
let neededHeight = width / ratio // This is a CGFloat like 133.2353
constraintPictureHeight.constant = neededHeight // Causes constraint error
constraintPictureHeight.constant = ceil(neededHeight) // All good!
このバグで私の頭をかいて数時間を費やした後、私はついに私のために働く解決策を見つけました。私の主な問題は、異なるセルタイプに対して複数のペン先を登録していましたが、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});
お役に立てれば!
内容に合わせてテキストビューのサイズを変更し、高さの制約定数を結果の高さに更新することで、UIView-Encapsulated-Layout-Height
制約の競合が解決されました。
[self.textView sizeToFit];
self.textViewHeightConstraint.constant = self.textView.frame.size.height;
私はこのようなメッセージを受け取っていました:
同時に制約を満たすことができません...
...
...
...
NSLayoutConstraint:0x7fe74bdf7e50 'UIView-Encapsulated-Layout-Height' V:[UITableViewCellContentView:0x7fe75330c5c0(21.5)]
...
...
制約NSLayoutConstraint:0x7fe0f9b200c0を破って回復を試みます。
私はカスタムの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-|
の違いが何であるかに関して少し謎です。しかしサイズを指定することは私にとって問題ではなく、それはログを取り除きます、そして私は私の必要な制約の優先順位を下げる必要はありません。
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
の優先度の下に最優先を設定する必要があります。