web-dev-qa-db-ja.com

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

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

IOS6でも問題なく動作し、iOS7でもlookになります

しかし、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]>

そして、実際私は望んでいないそのリストに制約の一つがあります:

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

translatesAutoresizingMaskIntoConstraintscontentViewプロパティをNOに設定することはできません=>セル全体を台無しにします。

44はデフォルトのセルの高さですが、Table View Delegateでカスタムの高さを定義したので、セルcontentViewにこの制約があるのはなぜですか?何がこれを引き起こす可能性がありますか?

IOS6ではそれは起きておらず、iOS6とiOS7の両方ですべてがうまく見えます。

私のコードは非常に大きいため、ここには投稿しませんが、必要な場合はお気軽にPastebinをお尋ねください。

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

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

また、なぜこれがiOS7でのみ起こるのかを理解することにも深く興味があります。

104
Alexis

私もこの問題を抱えていました。contentViewのフレームは、layoutSubviewsが呼び出されるまで更新されないようですが、セルのフレームは以前に更新され、contentViewのフレームは{0, 0, 320, 44}のまま制約が評価されるとき。

ContentViewをより詳細に見ると、自動サイズ変更マスクは設定されていないようです。

ビューを制約する前に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;
}
132
liamnichols

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

Static Table View Controllerは壊れやすいため、データソースまたは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でも同じです: iOS 7でのみ実行している場合、ストーリーボードプロトタイプセル(Xcode 6、iOS 8 SDK)のUICollectionViewCell contentViewのフレームの自動サイズ変更の問題が発生します

35
KoCMoHaBTa

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

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

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

13
Steven

ストーリーボードの良い解決策がまだ見つかりませんでした...ここにもいくつかの情報があります: 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"に置き換えます
  • ストーリーボードを右クリック
  • 名前を付けて開く-> Interface Builder
  • アプリを実行して出力を確認します
9
asdfasdfads

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

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

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

3
Vadim Yelagin

同じ問題がありました。上記の他の人に基づく私のソリューション:

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

ベスト、アレッサンドロ

1
Cormentis

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

0
Renetik

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

0
Centurion

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"/>
0
NSDeveloper