UITableViewCellのiOS7での自動レイアウト制約の問題


104

プログラムで自動レイアウト制約を使用してカスタムUITableViewセルをレイアウトし、セルサイズを正しく定義しています tableView:heightForRowAtIndexPath:

これは、iOS6にうまく働いていますし、それはありませんルックにもiOS7に罰金を

しかし、iOS7でアプリを実行すると、コンソールに次のようなメッセージが表示されます。

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.
2013-10-02 09:56:44.847 Vente-Exclusive[76306: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) 
(
        "<NSLayoutConstraint:0xac4c5f0 V:|-(15)-[UIImageView:0xac47f50]   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",
        "<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>",
        "<NSLayoutConstraint:0xac43680 V:[UIView:0xac4d0f0(1)]>",
        "<NSLayoutConstraint:0xac436b0 V:[UIView:0xac4d0f0]-(0)-|   (Names: '|':UITableViewCellContentView:0xd93e850 )>",
        "<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0xac43650 V:[UIImageView:0xac47f50]-(>=0)-[UIView:0xac4d0f0]>

そして確かに、そのリストには私が望まない制約の1つがあります。

"<NSAutoresizingMaskLayoutConstraint:0xac6b120 h=--& v=--& V:[UITableViewCellContentView:0xd93e850(44)]>"

translatesAutoresizingMaskIntoConstraintsプロパティcontentViewをNOに設定できない=>セル全体がめちゃくちゃになる。

44はデフォルトのセルの高さですが、テーブルビューのデリゲートでカスタムの高さを定義したので、セルのcontentViewにこの制約があるのはなぜですか?何が原因でしょうか?

iOS6ではそれは起こっておらず、iOS6とiOS7の両方ですべてが正常に見えます。

私のコードは非常に大きいため、ここには投稿しませんが、必要に応じてペーストビンをリクエストしてください。

セルの初期化で、私がそれをどのように行っているかを指定するには:

  • すべてのラベル、ボタンなどを作成します
  • translatesAutoresizingMaskIntoConstraintsプロパティをNO に設定しました
  • contentViewセルのサブビューとして追加します
  • に制約を追加します contentView

これがiOS7でのみ発生する理由を理解することにも興味があります。


カスタムセルの高さは何に設定されていますか?
Mike Pollard 2013年

カスタムセルの高さを90に設定
Alexis

同僚にも昨日同じ問題がありましたが、デフォルトのは320です(iPadアプリの場合)。
jrturton 2013年

この同じ問題を実証し、ここでサンプルプロジェクトがあります:github.com/Alex311/TableCellWithAutoLayout ここでは、その上に私の観察結果の一部を以下に示します。github.com/Alex311/TableCellWithAutoLayout/commit/...
smileyborg

同じエラーが発生しましたが、カスタムセルの高さを見つけるために使用していた余分なプロトタイプセルを初期化したことがないためです。
Steve Moser 14年

回答:


132

私にもこの問題がありました。layoutSubviewsが呼び出されるまでcontentViewのフレームは更新されないよう ですが、セルのフレームが先に更新され{0, 0, 320, 44}、制約が評価された時点でcontentViewのフレームが設定されたままになります。

contentViewを詳細に見てみると、autoresizingMaskが設定されていないようです。

ビューを制約する前にautoresizingMaskを設定すると、この問題を解決できます。

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
    if (self)
    {
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;
        [self loadViews];
        [self constrainViews];
    }
    return self;
}

これは仕事に感謝します。編集スタイルを使用するとどうなりますか?
Alexis

11
@ L14M333このコメントに投稿したコードをここで確認してください -基本的に、self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);制約を追加する前に設定できるだけで問題は解決します。
smileyborg 2013年

2
autoresizingMaskが機能しません。初期の制約はなくなりましたが、3つの新しいものが追加されました "<NSAutoresizingMaskLayoutConstraint:0x8b79740 h =-&-v =-&-UITableViewCellContentView:0x8b44010.height == UITableViewCellScrollView:0x8b4a130.height>"、 "<NSAutoresizingMaskLayoutConstraint:0x8b7b9f0 h =-&-v =-&-UITableViewCellScrollView:0x8b4a130.height == LibraryCell:0x8ac19d0.height>"、 "<NSAutoresizingMaskLayoutConstraint:0x8b7c590 h =-&v =-& 0x8ac19d0(0)]> "
カタロンフェタミン2014年

1
私もうまくいきます。1時間も苦労しています!ありがとう!<3
mokagio 2014

2
他の自動レイアウトの問題(iOS 7 / iOS 8)を取り除いた後、を使用することはを使用することself.contentView.bounds = CGRectMake(0, 0, 99999, 99999);と同じように機能することがわかりましたself.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth;。これをupdateConstraintsコンテンツビューに制約を追加する前に入れました。
テスト

35

iOS 8 SDKを使用しているiOS 7のUITableViewCellおよびUICollectionViewCellに問題があるようです。

セルが次のように再利用されると、セルのcontentViewを更新できます。

静的UITableViewControllerの場合:

#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
#if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_0

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [super tableView:tableView cellForRowAtIndexPath:indexPath];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }

    //your code goes here

    return cell;
}

#endif
#endif

静的テーブルビューコントローラーは壊れやすく、いくつかのデータソースまたはdeletegateメソッドを実装すると簡単に壊れる可能性があるため、このコードがiOS 7でのみコンパイルおよび実行されることを確認するチェックがあります

標準の動的UITableViewControllerの場合と同様です。

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellID = @"CellID";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];

    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
    {
        cell.contentView.frame = cell.bounds;
        cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    }
    //your code goes here       
    return cell;
}

この場合、このメソッドを実装する必要があるため、コンパイルの追加チェックは必要ありません。

このスレッドでコメントされているように、アイデアはどちらの場合でもUICollectionViewCellでも同じです。ストーリーボードプロトタイプセル(Xcode 6、iOS 8 SDK)でのUICollectionViewCell contentViewのフレームの自動サイズ変更の問題は、iOS 7でのみ実行される場合に発生します。


1
これが最良の答えです。少なくとも私にとっては最良の解決策です。私のセル(Autolayoutルール)は、iOS 8でXCode6を使用して機能し、iOS7および6でXCode 5を使用して機能しました。XCodeをXCode6に更新すると、iOS6および7では機能しなくなります。
xarly

これはXcode 6.1の問題ではなくなりました。また、NSFoundationVersionNumberは使用しないでください。nshipster.com/ swift
system

1
@ onmyway133:なぜこれがXcode 6.1で問題にならないのですか?Xcode 6.1とiOS 8.1 SDKを使用しても問題は解決しません。この問題はiOS 7でのみ発生します。境界を変更するか、自動サイズ変更マスクを設定すると、問題が解決します。しかし、私は最も投票された回答またはそのコメントで述べられているアプローチを使用しました。
テスト

はい、これは私の3時間のグーグル検索に基づく最良の答えです。他の同様の「ソリューション」は、cell.contentView.autoresizingMaskの完全なリストを提供しません。これだけはXcodeの6で作成した私のiPad 7.1のプロジェクトのために働く
ゴールデン親指

13

セルは再利用されており、高さはコンテンツに基づいて変化する可能性があるため、一般的には、間隔の優先度を必要以上に設定しない方がよいと思います。

あなたの場合、UIImageViewの上部への間隔は15で、下部のビューの下部への間隔は0です。これらの制約の優先度を999(1000ではなく)に設定した場合、制約は必要ないため、アプリはクラッシュしません。

layoutSubviewsメソッドが呼び出されると、セルの高さが正しくなり、制約を通常どおり満たすことができます。


あなたは天才です!素敵でクリーンなソリューションに感謝します:)
Blacky

9

ストーリーボードの良い解決策がまだ見つかりませんでした...いくつかの情報もここにあります:https : //github.com/Alex311/TableCellWithAutoLayout/commit/bde387b27e33605eeac3465475d2f2ff9775f163#commitcomment-4633188

彼らがそこでアドバイスしたことから:

self.contentView.bounds = CGRectMake(0, 0, 99999, 99999);

私は自分の解決策を誘発しました:

  • ストーリーボードを右クリック
  • 別名で開く->ソースコード
  • そこで文字列「44」を検索します
  • それは次のようになるでしょう

<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="none" allowsSelection="NO" rowHeight="44" ...
    <tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="ChatMessageCell" id="bCG-aU-ivE" customClass="ChatMessageCell">
        <rect key="frame" x="0.0" y="22" width="320" height="44"/>

  • rowHeight = "44"をrowHeight = "9999"に、height = "44"をheight = "9999"に置き換えます
  • ストーリーボードを右クリック
  • 別名で開く->インターフェースビルダー
  • アプリを実行して出力を確認する

これでうまくいきました。クラスをインスタンス化することにより、一部のセルがプロトタイプから作成され、他のセルが完全にコードで作成されるUITableViewControllerをストーリーボードに作成しました。
Atharva 2015

3

デフォルトのセルの高さを増やすだけです。問題は、セルのコンテンツがデフォルトの(初期)セルサイズよりも大きく、セルが実際のサイズにサイズ変更されるまで、いくつかの非負の制約に違反しているようです。


実際、私のセルはデフォルトサイズよりも背が高くなっていますが、テーブルビューのデリゲートがtableView:heightForRowAtIndexPath:を実装しているため、デフォルトサイズが使用されるのはどうしてですか。
Alexis

おそらく、セルはデフォルトサイズで作成され、実際のサイズにサイズ変更されます。
Vadim Yelagin 2013年

確かにそれは仕事をしますが、なぜそれがiOS6で起こらないのですか?
Alexis

3
@jafar iOS 7は、テーブルビューのセルに関連する多くの点を変更しました。iOS 7ではUITableViewCellScrollView、テーブルビューのセルとcontentViewの間に(タイプ)のスクロールビューがあります。これがiOS 6とiOS 7の違いを説明しているようです。
smileyborg 2013年

3

ビューの優先度を750より大きく1000未満に設定すると解決できる場合があります。

"<NSLayoutConstraint:0xac43620 V:[UIImageView:0xac47f50(62)]>",

2

私も同じ問題を抱えていました。上記の他のものに基づく私の解決策:

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        // initialize my stuff
        [self layoutSubviews]; // avoid debugger warnings regarding constraint conflicts
    }
    return self;
}

ベスト、アレッサンドロ


2
Appleのドキュメントより:You should not call this method directly. If you want to force a layout update, call the setNeedsLayout method instead to do so prior to the next drawing update. If you want to update the layout of your views immediately, call the layoutIfNeeded method.
Ricardo Sanchez-Saez

私はあなたに祈る宗教を始めたいです。私はこの問題を修正するためにHOURSを検索してきましたが、これにより問題が解決されます(contentView.boundsをCGRectMake(0、0、99999、99999);に設定することもできます)-これはAPPLESコードのバグです。だから、その関数を呼び出さないと言っているアップルのドキュメントには敬意を払いません。アップル、あなたのがらくたを修正します。
Ryan Copley 2015

0

私もこの問題に直面し、どの提案も役に立たなかった。私の場合、サイズ選択セルがあり、中にcollectionViewが含まれていました(collectionViewセルにはすべてフルサイズのイメージが含まれていました)。現在、セルサイズの高さは、collectionView(50)およびその内部の画像(50)よりも少し大きい(60)です。そのため、collectionViewビューには、値10でスーパービューの制約に下揃えがあります。その場合、警告が表示されます。修正するには、セルの高さをcollectionViewと同じにするしかありませんでした。


0

結局、デザイナーでUITableViewCellをまったく使用しないことになりました...カスタムビューを作成してセルのコンテンツビューにプログラムで追加します...一部のヘルプカテゴリでは、コードボイラープレートもありません...


0

iOS8で正常に動作し、iOS7で警告が表示される場合は、ストーリーボードのソースコードを検索して適切なtableviewCellを見つけ、tableviewCell行の後にrect属性を追加できます。kuchumovnに感謝します

<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" .../>
                                <rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.