ストーリーボードプロトタイプセル(Xcode 6、iOS 8 SDK)のUICollectionViewCell contentViewのフレームの自動サイズ変更の問題は、iOS 7でのみ実行すると発生します


158

Xcode 6 Beta 3、iOS 8 SDKを使用しています。Swiftを使用してターゲットiOS 7.0をビルドします。以下のスクリーンショットを使用して、私の問題を段階的に参照してください。

StoryboardにUICollectionViewがあります。中央に1つのラベルを含むプロトタイプUICollectionViewCell(自動サイズ変更ルールなし)。紫色の背景は、実行時に生成されたContentViewをマークすることでした。そのビューは、UICollectionViewLayoutDelegateに基づいて適切にサイズ変更されますが、iOS 7では変更されません。Xcode6を使用しているため、問題はiOS 7でのみ発生します。

iOS 8でアプリをビルドするとき。すべてが大丈夫です。

注:紫はcontentView、青は角が丸いUIButtonです。

http://i.stack.imgur.com/uDNDY.png

ただし、iOS 7では、セル内のすべてのサブビューが突然(0,0,50,50)のフレームに縮小され、自動サイズ変更ルールに準拠しなくなります。

http://i.stack.imgur.com/lOZH9.png

これはiOS 8 SDKまたはSwift、あるいはXcodeのバグだと思いますか?


更新1:この問題は公式のXcode 6.0.1にも存在します!最善の回避策は、セルのcellForItemにフレームを設定することにより、KoCMoHaBTaが以下に提案したもののようです(ただし、セルをサブクラス化する必要があります)。これはiOS 8 SDKとiOS 7の間の非互換性であることが判明しました(Appleから引用された以下のecotaxの回答を確認してください)。

更新2: このコードをcellForItemの先頭に貼り付けます。問題はありません。

/** Xcode 6 on iOS 7 hot fix **/
cell.contentView.frame = cell.bounds;
cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
/** End of Xcode 6 on iOS 7 hot fix **/

1
この問題はXcode 6 Beta 5にも存在することがわかりました。誰もがこれを経験しましたか?
2014

2
私のプロジェクトでは、現在この問題に取り組んでいます。Xcode 5を使用してビルドされたiOS 7およびiOS 8は問題なく表示されます。Xcode 6ベータ6を使用してビルドされたiOS 8は問題ありません。Xcode 6ベータ6を使用してビルドされたiOS 7には、あなたが説明している問題があります。Revealを使用すると、UICollectionViewCellのサイズが適切に設定されていることがわかります。ただし、セルのcontentViewは、親であるにもかかわらずサイズ変更されませんでした。UICollectionViewCellでAutoresize Subviewsがオンになっています。contentViewのサイズは、ストーリーボードのサイズに設定されます。このプロジェクトでは自動レイアウトを使用していません。私のプロジェクトは完全に客観的ですc。
Del Brown

2
私はこの問題がXcode 6 / iOS 8 GMシードの時点でまだ存在していることを付け加えたかっただけです。@DanielPlamannの回答をcontentViewセルに合わせて強制的にサイズ変更することで、問題を回避できます。iOS 8では、AppleはセルビルダーのビューがInterface Builderで作成されたときの処理方法に何らかの変更を加えたと思います(いずれにしても、それはまだブラックボックスです)。しかし、iOS 7をターゲットにすると動作が変わるというのは確かにバグです。
Stuart

Xcode 6 GM、自動レイアウト、ペン先ベースのセルでも同じです。contentViewエッジをセルのエッジに固定することで修正します。
sergiou87 2014

3
xcode 6.1をダウンロードしましたが、シミュレータで同じ問題がまだ発生します。
Haitao Li 2014

回答:


169

contentViewが壊れています。awakeFromNibでも修正できます

ObjC:

- (void)awakeFromNib {

    [super awakeFromNib];

    self.contentView.frame = self.bounds;
    self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}

Swift3:

override func awakeFromNib() {
    super.awakeFromNib()

    self.contentView.frame = self.bounds
    self.contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
}

3
self.contentView.frame = self.boundsなしでトリックを行いましたか?必要だと思いますか?とにかくありがとう!
Michal Shatz 2014

こんにちはミハル、あなたに同意します。しかし、100%確実にするためには、次のiOSでそれを追加する方がうまくいくと思います。
イゴールパラグタ2014

5
私はこの答えが好きですが、[super awakeFromNib]を呼び出す必要があります。また、iOS 7.1以下のチェックを追加することも考えています。これらのサイズ変更マスクを追加すると、iOS8のデフォルトの動作にどのように影響するかわかりません。
GingerBreadMane 2014

あなたがニブやストーリーボードを使用していない場合、これはまた、あなたがapplyLayoutAttributesに入れた場合に動作します:
cetcet

これは私にはうまくいきません。Autolayoutを使用していません。何か援助は?
thatzprem 2014

61

同じ問題が発生し、Apple DTSに助けを求めました。彼らの回答は:

iOS 7では、セルのコンテンツビューは、自動サイズ変更マスクによってサイズが調整されました。iOS 8ではこれが変更され、セルは自動サイズ変更マスクの使用を停止し、layoutSubviewsのコンテンツビューのサイズ変更を開始しました。nibがiOS 8でエンコードされてからiOS 7でデコードされた場合、自動サイズ変更マスクなしでコンテンツビューが表示され、他の方法でサイズ変更することはできません。したがって、セルのフレームを変更した場合、コンテンツビューは追跡されません。

iOS 7に展開しているアプリは、コンテンツビュー自体のサイズ変更、自動サイズ変更マスクの追加、または制約の追加により、これを回避する必要があります。

これは、XCode 6のバグではなく、iOS 8 SDKとiOS 7 SDKの間の非互換性であることを意味していると思います。Xcode6にアップグレードすると、iOS 8 SDKの使用が自動的に開始されるためです。

以前にコメントしたように、ダニエル・プラマンの回避策は私のために作品を説明しました。Igor PalagutaとKoCMoHaBTaによって記述されたものはより単純に見え、Apple DTSの答えを出すのに意味があるように思われるので、後でそれらを試します。


これは面白いですが、私は彼らがそれを修正することを望みます。この動作は、iPhone 6のサポートを追加したXcode 6 GMでのみ導入されました。以前のベータでは問題なく動作していました。気づいたプロジェクトを以前のベータ版に戻し、期待どおりに機能しました。この問題について、Appleにバグを報告してください。
arton、2014

@arton私はDTSに助けを求めたその日にバグレポートを提出しました。18312246の複製としてクローズされました。これがどれだけ役立つかはわかりません。
ecotax 2014年

私はContentViewのサイズを変更することで回避策を使用し、私のために機能します。-(CGSize)collectionViewContentSize {return CGSizeMake(self.collectionView.bounds.size.width、self.collectionView.bounds.size.height); }
ヘススHurtadoの

60

私は同じ問題に遭遇し、Appleが次のXcodeバージョンでこれを修正することを期待しています。その間、私は回避策を使用します。私のUICollectionViewCellサブクラスlayoutSubviewsでは、サイズがサイズと異なる場合に備えて、contentViewをオーバーライドして手動でサイズ変更しましたcollectionViewCell

- (void)layoutSubviews
{
  [super layoutSubviews];

  BOOL contentViewIsAutoresized = CGSizeEqualToSize(self.frame.size, self.contentView.frame.size);

  if( !contentViewIsAutoresized) {
    CGRect contentViewFrame = self.contentView.frame;
    contentViewFrame.size = self.frame.size;
    self.contentView.frame = contentViewFrame;
  }
}

ええ、私は同様の回避策を使用しましたが、cellForItem / cellForRowでも同様に機能しました。
2014

1
これが最良の解決策です。これをcellForItem / cellForRowに追加すると、デバイスを回転させているときにセルサイズが変更されると、奇妙なアーティファクトが発生します。
spybart 14

こんにちは!このコードで問題が発生しました。boolean contentViewIsAutoresizedがストーリーボードまたはプロトタイプセルから読み込まれた場合、初めてtrueになります。reloadDataを実行した場合にのみ、2番目は正しいデータになります。したがって、実際にサイズを確認する必要はありません。代わりに次のようにしてください:self.contentView.frame = self.bounds;
2014

確認済み:cellForItemまたはcellForRowで行う必要があります。これは、layoutSubviewsが呼び出されるのは、セルが返された後であるからです。描画など、その前に行うことはすべて誤って計算されます。
2014

1
[cell layoutIfNeeded];ええと、cellForItemまたはcellForRow に配置する方が良いでしょうか?
wtorsi 2014

38

別の解決策は、contentViewのサイズと自動サイズ変更マスクを-collectionView:cellForItemAtIndexPath:次のように設定することです。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

     static NSString *cellID = @"CellID";

     UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];

     // Set contentView's frame and autoresizingMask
     cell.contentView.frame = cell.bounds;
     cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;

     // Your custom code goes here

     return cell;
}

自動サイズ変更マスクは制約に変換されるため、これは自動レイアウトでも機能します。


2
これは、サブクラス化なしで任意のセルタイプで機能し、コレクションビューで複数のタイプのセルを使用している場合に複数の場所で変更する必要がないため、優れたソリューションです。
ナクロス2014年

6

Xcode 6.0.1では、UICollectionViewCellのcontentViewがiOS7デバイスで壊れています。また、awakeFromNibまたはinitメソッドでUICollectionViewCellとそのcontentViewに適切な制約を追加することで修正できます。

        UIView *cellContentView = self.contentView;
        cellContentView.translatesAutoresizingMaskIntoConstraints = NO;

        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[cellContentView]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(cellContentView)]];
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[cellContentView]|"
                                                                     options:0
                                                                     metrics:0
                                                                       views:NSDictionaryOfVariableBindings(cellContentView)]];

これだけが機能するようになりました。IOS8の場合のみ実行する必要があります。デキューするたびに呼び出す必要があります。しかし、これはまた、複数の選択理由、それは視覚的に必要として...仕事をしないでください理想的なソリューションではありません
Renetik

ベストは、あなたが簡単な場合に使用する自動レイアウトイベントによって皮肉にも時間を節約するこのバグで、本当に自動レイアウトを使用することです。..
Renetik

マスクは私には効きません。ただし、制約の設定は機能します!
エントロピー2015年

4

Xcodeがxibファイルをnib形式にコンパイルする方法に関するXcode 6 GMのバグのため、これは他の言及された回避策がないと正しく機能しません。100%確実であるとは言えませんが、それはXcode関連であり、ランタイムとは関係ありませんが、非常に自信があります。これを示す方法を次に示します。

  1. Xcode 5.1でアプリケーションをビルドして実行します。
  2. シミュレーターアプリケーションのディレクトリに移動し、問題が発生しているxibのコンパイル済み.nibファイルをコピーします。
  3. Xcode 6 GMでアプリケーションをビルドして実行します。
  4. アプリケーションを停止します。
  5. 新しくビルドされたアプリケーションのシミュレーターフォルダー内の.nibファイルを、Xcode 5.1を使用して作成された.nibファイルに置き換えます。
  6. Xcodeからではなく、シミュレータからアプリを再起動します。
  7. その.nibからロードされたセルは期待どおりに機能するはずです。

私は、この質問を読んだすべての人がレーダーをアップルに提出することを願っています。これは大きな問題であり、最終的なXcodeリリースの前に対処する必要があります。

編集:ecotaxの投稿踏まえて、これを更新して、iOS 8とiOS 7でのビルドの動作の違いは確認されましたが、バグではないことを伝えたいと思います。iOS 7でビルドすると、この作業を行うために必要なコンテンツビューに自動サイズ変更マスクが追加されたため、私のハックで問題が修正されました。


彼らが合法的にGMバージョンとは異なるxCodeをリリースできるかどうかはわかりません
Mabedan '16

彼らは刑務所に行きますか?= Pしかし、真剣に、彼らができることを確認してください。覚えていなければ、彼らはマーベリックスのために複数のGMバージョンを持っていました。あまり一般的ではありませんが、発生する可能性があります。
Acey、2014

4

この投稿の答えは、私が理解できなかった理由です。

まず、2つの「ルール」があります。

  1. プログラムで作成されたビュー(例[UIView new])の場合、プロパティtranslatesAutoresizingMaskIntoConstraintsYES
  2. AutoLayoutを有効にしてインターフェースビルダーで作成されたビューでは、プロパティが次のようにtranslatesAutoresizingMaskIntoConstraints設定されます。NO

2番目のルールは、制約を定義していないトップレベルのビューには適用されないようです。(例:コンテンツビュー)

Storyboardセルを見ると、セルがcontentView露出していないことに注意してください。contentViewAppleはを「管理」していない。

ストーリーボードのソースコードを詳しく見て、contentViewセルがどのように定義されているかを確認します。

<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">

セルのサブビュー(に注意translatesAutoresizingMaskIntoConstraints="NO"):

<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NaT-qJ-npL" userLabel="myCustomLabel">

contentViewそれはですがないtranslatesAutoresizingMaskIntoConstraintsに設定しますNO。さらに、おそらく@ecotaxの発言が原因で、レイアウトの定義が欠けています。

を調べるcontentViewと、自動サイズ変更マスクがありますが、定義はありません。 <autoresizingMask key="autoresizingMask"/>

したがって、2つの結論があります。

  1. contentView translatesAutoresizingMaskIntoConstraintsに設定されていYESます。
  2. contentView レイアウトの定義が不足しています。

これは私たちが話し合った2つの解決策につながります。

自動サイズ変更マスクは手動で設定できますawakeFromNib

self.contentView.frame = cell.bounds;
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

または、contentView translatesAutoresizingMaskIntoConstraintsNOに設定して、awakeFromNibで制約を定義できます- (void)updateConstraints


4

これは、@ Igorの回答のSwiftバージョンであり、これは受け入れられ、素敵な回答相手に感謝します。

最初にUICollectionViewCellサブクラスに移動し、次のコードをクラス内に貼り付けます。

override func awakeFromNib() {
    super.awakeFromNib()
    self.contentView.frame = self.bounds
    self.contentView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
}

ちなみに私はXcode 7.3.1とSwift 2.3を使用しています。ソリューションは、完璧に動作しているiOS 9.3でテストされています。

おかげで、これが役に立てば幸い。


私の悪い英語で申し訳ありませんが、私は「魅力のように働く」ことを意味しました:)
Aznix

@Aznix問題なし.. :)
onCompletion

2

すばやく、次のコードをコレクションビューのセルサブクラスに配置します。

override var bounds: CGRect {
  didSet {
    // Fix autolayout constraints broken in Xcode 6 GM + iOS 7.1
    self.contentView.frame = bounds
  }
}

これが私が探していた答えでした。私はObjective-CでsetBoundsをオーバーライドしてこの問題を修正していました(Swiftでの記述方法がわかりませんでした)。ありがとうございました:)
Matthew Cawley

1

contentViewiOS 8のサイジングにも問題があることを発見しました。これは、サイクルの非常に遅くレイアウトされる傾向があり、一時的な制約の競合を引き起こす可能性があります。これを解決するために、次のメソッドをのカテゴリに追加しましたUICollectionViewCell

- (void)fixupContentView
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED < 80100
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1) {
        self.contentView.frame = self.bounds;
        self.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
    } else {
        [self layoutIfNeeded];
    }
#endif
#endif
}

このメソッドは、セルをデキューした後に呼び出す必要があります。


このメソッドが自動的に呼び出されると理想的です。私はそれが好きではありませんが、これはスウィズリングによって行うことができますdequeueReusableCellWithReuseIdentifier:forIndexPath:
ファットマン2014年

Appleは、Xcode 6.1 GM(ビルド6A1042b)のiOS SDKバージョン8.1でこの問題を修正したようです。したがって、8.1 SDKを使用するときに実行されないように上記のコードを更新しました。チームがすべてXcode 6.1に移行したら、このハックを完全に削除できます。
ファットマン

1

私はこれを修正しました:

override func layoutSubviews() {
   contentView.superview?.frame = bounds
   super.layoutSubviews()
}

参照:ここ


-1

そのコレクションビューセルのnibにあるチェックボックス「サブビューの自動サイズ変更」をチェックしてください。iOS 8とiOS 7の両方で正常に動作します。


いいえ、ありません。埋め込み型プロトタイプセルです。
2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.