web-dev-qa-db-ja.com

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

Xcode 6 Beta 3、iOS 8 SDKを使用しています。 Swiftを使用してTarget iOS 7.0をビルドします。以下のスクリーンショットを使用して、問題をステップごとに参照してください。

StoryboardにUICollectionViewがあります。 1プロトタイプUICollectionViewCellには、中央に1つのラベルが含まれます(自動サイズ変更ルールはありません)。紫色の背景は、セルによって実行時に生成される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 **/
157
thkeen

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]
}
167
Igor Palaguta

同じ問題に遭遇し、Apple DTSに助けを求めました。彼らの返事は:

IOS 7では、セルのコンテンツビューは、自動サイズ変更マスクを使用して自身のサイズを変更しました。 iOS 8ではこれが変更され、セルは自動サイズ変更マスクの使用を停止し、layoutSubviewsのコンテンツビューのサイズ変更を開始しました。ペン先がiOS 8でエンコードされ、次にiOS 7でデコードされる場合、自動サイズ変更マスクなしでコンテンツビューが表示され、それ以外の方法でサイズを調整することはできません。そのため、セルのフレームを変更した場合、コンテンツビューは追従しません。

IOS 7に戻ってデプロイするアプリは、コンテンツビュー自体のサイズ変更、自動サイズ変更マスクの追加、または制約の追加により、この問題を回避する必要があります。

これは、XCode 6のバグではなく、iOS 8 SDKとiOS 7 SDKの非互換性であり、Xcode 6にアップグレードすると、iOS 8 SDKの使用が自動的に開始されるため、ユーザーに打撃を与えます。

前にコメントしたように、回避策のダニエル・プラマンが作品を説明してくれました。しかし、Igor PalagutaとKoCMoHaBTaによって記述されたものは、よりシンプルに見え、Apple DTSの答えを与える意味があるように見えるので、後で試してみます。

61
ecotax

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

- (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;
  }
}
60
Daniel Plamann

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

- (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;
}

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

38
KoCMoHaBTa

Xcode 6.0.1では、iOS7デバイスのUICollectionViewCellのcontentViewが壊れています。また、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)]];
6
SerJ_G

これは、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からロードされたセルは期待どおりに動作するはずです。

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

編集: ecotaxの投稿 に照らして、これを更新して、iOS 8とiOS 7のビルドの動作の違いが確認されたが、バグではないことを伝えました。この問題を修正したのは、iOS 7でビルドすると、この機能を実現するために必要なコンテンツビューに自動サイズ変更マスクが追加され、Appleが追加されなくなったためです。

4
Acey

これは、@ 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でテストされています。

ありがとう、これが役に立てば幸いです。

4
onCompletion

この投稿での答えは、私が理解したことはありませんwhy.

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

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

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

Storyboardセルを見ると、セルのcontentViewが公開されていないことに注意してください。 contentView、Appleは「制御」していません。

ストーリーボードのソースコードを詳しく見て、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には、translatesAutoresizingMaskIntoConstraintsNOに設定されていません。さらに、おそらく @ ecotax said が原因で、レイアウト定義が不足しています。

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

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

  1. contentViewtranslatesAutoresizingMaskIntoConstraintsYESに設定されます。
  2. contentViewにはレイアウトの定義がありません。

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

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

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

または、contentViewtranslatesAutoresizingMaskIntoConstraintsNOawakeFromNibに設定し、- (void)updateConstraintsで制約を定義できます。

4
kgaidis

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

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

IOS 8ではcontentViewのサイジングにも問題があることがわかりました。これは、サイクルの非常に遅くにレイアウトされる傾向があり、一時的な制約の競合を引き起こす可能性があります。これを解決するために、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
}

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

1
phatmann

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

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

参照: ここ

1
Serluca