38

UICollectionView を使用して、全画面 (ステータス バーとナビゲーション バーを除く) をカバーするセルを表示しています。セル サイズは次のように設定されself.collectionView.bounds.sizeます。

- (void)viewWillAppear:(BOOL)animated
{
    //
    // value isn't correct with the top bars until here
    //
    CGSize tmpSize = self.collectionView.bounds.size;
    _currentCellSize = CGSizeMake( (tmpSize.width), (tmpSize.height));
}

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout*)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    return _currentCellSize;
}

これにより、各デバイスの正しいサイズが設定されます。各セルにはインセットがないように定義されており、レイアウトにはヘッダーまたはフッターがありません。ただし、縦向きから横向きに回転すると、次の「苦情」が発生します。

the behavior of the UICollectionViewFlowLayout is not defined because:
the item height must be less that the height of the UICollectionView minus the section insets top and bottom values.

このエラーは理解できましたが、セルのサイズをリセットし、ローテーション トランジションに組み込まれたフロー レイアウトを使用します。

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    //self.collectionView.bounds are still the last size...not the new size here
}
- (void)didRotateFromInterfaceOrientation: UIInterfaceOrientation)fromInterfaceOrientation
{
    CGSize tmpSize = self.collectionView.bounds.size;
    _currentCellSize = CGSizeMake( (tmpSize.width), (tmpSize.height));
    [self.collectionView performBatchUpdates:nil completion:nil];//this will force the redraw/size of the cells.
}

セルはランドスケープで正しくレンダリングされます。

フロー レイアウトは古いセル サイズを認識しているように見えますが (高すぎるため、問題が発生します)、新しいセル サイズ セットを読み取り/レンダリングしますdidRotateFromInterfaceOrientation

苦情を取り除く方法はありますか?

デバイスの回転遷移中に、(現在の画面サイズに対して) 正しいターゲット画面サイズにアクセスできる別のフックを見つけようとしましたが、うまくいきませんでした。デバッグ出力は、苦情が のwillRotateToInterfaceOrientation前後に発生したことを示していdidRotateFromInterfaceOrientationます。

また、明らかなことを確認しました。セルの高さを横長の画面の高さよりも小さい固定サイズに設定すると、苦情は発生しません。また、横向きから縦向きに戻すときも苦情は発生しません。

すべてが正常に実行され、正しくレンダリングされます。しかし、この苦情は私たちを心配させます。他にアイデアや解決策はありますか?

4

21 に答える 21

36

私は同じ警告を受けていました。「reloadData」アプローチに満足できなかったので、コレクション ビューのフレームを設定する[self.collectionView.collectionViewFlowLayout invalidateLayout] 前に呼び出しを行うと、警告が消え、期待どおりの結果が得られることがわかりました。

于 2013-03-25T20:28:02.413 に答える
9

この荷を積んだ、まだ受け入れられていないバービーに別のエビを投げないでください.

- (CGSize)collectionView:(UICollectionView *)collectionView 
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath {

    [collectionView setContentInset:UIEdgeInsetsMake(0, 0, 0, 0)];
    return CGSizeMake(100, collectionView.frame.size.height);
}

セルサイズを返す直前にコンテンツインセットを設定すると、うまくいきました。

ノート:

ストーリーボードでコンテナー ビューを使用して、UIViewController 内にコレクション ビューをロードしています。ストーリーボードのflowLayoutオブジェクトにこれを設定してみました。ストーリーボードのコレクション ビュー。そして、UICollectionViewDelegateFlowLayout の 1 つをオーバーライドします。どちらかは覚えていませんが。これが垂直レイアウトで機能するかどうかもわかりません。

于 2014-06-27T21:30:07.833 に答える
6

[UIViewController willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration]

に電話しましたが、[UICollectionViewLayout invalidateLayout]うまく機能しているようです。

于 2013-07-11T01:44:00.463 に答える
4

多くの解決策は追加invalidateLayoutを提案してwillAnimateRotationToInterfaceOrientationいますが、これは iOS 8 以降非推奨です。

iOS 8 以降の場合は、次を使用します。

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];

    [self.collectionView.collectionViewLayout invalidateLayout];
}

@ user7097242 のコメントのおかげで、swift4 バージョンは次のようになります。

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    self.collectionView.collectionViewLayout.invalidateLayout()
}
于 2016-03-31T12:49:46.330 に答える
2

これで解決しました:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [self.collectionView.collectionViewLayout invalidateLayout];
}

そして、サイズを設定するためにこのデリゲートメソッドを使用しています:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

そこから、回転後に正しいフレームでこれを使用できます。

self.collectionView.frame.size
于 2014-02-25T09:17:04.130 に答える
2

ナビゲーション バーを半透明にする必要があったため、IB のビュー コントローラーの [スクロール ビュー インセットの調整] のチェックを外すだけで簡単に修正できました。

于 2014-11-03T08:37:45.743 に答える
2

同じ問題に遭遇して修正しました。私の解決策はあなたが求めていたものに沿ったものであり、既存の回答と一致しないため、ここに投稿しました.

#define NUMBER_OF_CELLS_PER_ROW 1

- (UICollectionViewFlowLayout *)flowLayout {
    return (UICollectionViewFlowLayout *)self.collectionViewLayout;
}

- (CGSize)itemSizeInCurrentOrientation {
    CGFloat windowWidth = self.collectionView.window.bounds.size.width;

    CGFloat width = (windowWidth - (self.flowLayout.minimumInteritemSpacing * (NUMBER_OF_CELLS_PER_ROW - 1)) - self.flowLayout.sectionInset.left - self.flowLayout.sectionInset.right)/NUMBER_OF_CELLS_PER_ROW;

    CGFloat height = 80.0f;

   return CGSizeMake(width, height);
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
    [self.flowLayout invalidateLayout];
    self.flowLayout.itemSize = [self itemSizeInCurrentOrientation];
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    // Now that the rotation is complete, load the cells.
    [self.collectionView reloadData];
}
于 2013-10-22T16:45:18.040 に答える
2

これは私にとってはうまくいきます:(そしてあなたにもうまくいくことを願っています!)

- (void)viewWillLayoutSubviews 
{     
     self.flowLayout.itemSize = CGSizeMake(self.collectionView.bounds.size.width/4,self.collectionView.bounds.size.height);    
     [self.flowLayout invalidateLayout];
}

- (void)viewDidLayoutSubviews     
{
    self.flowLayout.itemSize = CGSizeMake(self.collectionView.bounds.size.width/4,self.collectionView.bounds.size.height); 
}
于 2015-04-03T07:50:13.147 に答える
0

UICollectionViewFlowLayoutInvalidationContext同じコンテンツ オフセットを維持するように新しいオフセットを計算する を使用しました。私自身の関数collectionViewSizeForOrientation:は適切なサイズを返します。完璧ではありませんが、少なくとも大ざっぱではありません。

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    CGSize fromCollectionViewSize = [self collectionViewSizeForOrientation:[self interfaceOrientation]];
    CGSize toCollectionViewSize = [self collectionViewSizeForOrientation:toInterfaceOrientation];

    CGFloat currentPage = [_collectionView contentOffset].x / [_collectionView bounds].size.width;
    NSInteger itemCount = [_collectionView numberOfItemsInSection:0];

    UICollectionViewFlowLayoutInvalidationContext *invalidationContext = [[UICollectionViewFlowLayoutInvalidationContext alloc] init];

    [invalidationContext setContentSizeAdjustment:CGSizeMake(toCollectionViewSize.width * itemCount - fromCollectionViewSize.width * itemCount, toCollectionViewSize.height - fromCollectionViewSize.height)];
    [invalidationContext setContentOffsetAdjustment:CGPointMake(currentPage * toCollectionViewSize.width - [_collectionView contentOffset].x, 0)];

    [[_collectionView collectionViewLayout] invalidateLayoutWithContext:invalidationContext];

    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
}

collectionViewSizeForOrientation:私の場合、インセットとアイテムの間隔が0であると仮定すると、次のようになります:

- (CGSize)collectionViewSizeForOrientation:(UIInterfaceOrientation)orientation
{
    CGSize screenSize = [[UIScreen mainScreen] bounds].size;

    CGFloat width = UIInterfaceOrientationIsLandscape(orientation) ? MAX(screenSize.width, screenSize.height) : MIN(screenSize.width, screenSize.height);
    CGFloat height = UIInterfaceOrientationIsLandscape(orientation) ? MIN(screenSize.width, screenSize.height) : MAX(screenSize.width, screenSize.height);

    return CGSizeMake(width, height);

}

于 2014-11-03T15:59:04.263 に答える
0

UICollectionView のフレームのサイズを変更するときに、同じ問題に遭遇しました。FlowLayout でデリゲート メソッドを使用してセルのサイズを返す場合 (これは、含まれている UICollectionView のサイズに基づいて更新されます)、UICollectionView のフレームのサイズを変更 (小さく) すると、エラー メッセージが表示されます。不平を言う前に、デリゲートに更新されたサイズ情報を要求していないようでした。最終的には、再描画時にデリゲート メソッドにサイズ情報を要求しますが、新しいフレーム メソッドを割り当てた時点でまだ警告が発行されます。警告を取り除くために、UICollectionViewFlowLayout オブジェクトの itemSize プロパティを明示的に設定してからフレームを新しい小さい値に設定しました。私の状況は非常に単純なので、デリゲート メソッドに依存するのではなく、この時点で itemSize の計算を実行するだけで済むと思います (コレクション ビュー内のすべてのアイテムが同じサイズであるため)。デリゲート メソッドを実装したまま itemSize プロパティを設定するだけでは、問題は解決しませんでした。デリゲート メソッドが実装されていることが検出された場合、itemSize の値は無視されたと思います (存在することがわかっている場合は、なぜそれを呼び出さないのですか)。 ?!)。これが役に立てば幸いです。おそらく、回転の前に itemSize を明示的に設定することもできます。

于 2013-02-06T18:26:21.123 に答える
0

注: 私の場合、問題のpreferredContentSizeプロパティを設定していることがわかりましUIViewControllerた。これがあなたのケースであることがわかった場合は、UICollectionViewDelegateFlowLayoutプロトコルの次の方法に対処する必要がある場合があります。

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    CGSize size = collectionViewLayout.collectionView.bounds.size;
    ...
    return size;
}
于 2016-03-01T22:24:58.423 に答える
0

didRotateFromInterfaceOrientation の最後で試してください:

[self.collectionView setNeedsLayout]

うまくいかない場合は、このすべてのものを didRotateFromInterfaceOrientation から willRotateToInterfaceOrientation に移動してみてください

于 2015-11-15T16:42:45.557 に答える
0

iOS 7 でこれらの警告を黙らせる解決策を見つけようとするのは、私には困難でした。最終的に my のサブクラス化に頼ってUICollectionView、次のコードを追加しました。

- (void)setFrame:(CGRect)frame
{
    if (!iOS8 && (frame.size.width != self.frame.size.width))
    {
        [self.collectionViewLayout invalidateLayout];
    }

    [super setFrame:frame];
}

で全体のサイズをチェックしたい人もいるかもしれませんCGSizeEqualToSize()

于 2015-03-25T01:32:22.913 に答える
0

サブクラス化UICollectionViewしてオーバーライドできますsetBounds:。アイテムのサイズを呼び出す前[super setBounds:]に、新しい境界に合わせて調整できます。はスクロール中にも呼び出される
ため、境界のサイズが変更されたかどうかを確認する必要があります。setBounds:

于 2013-07-28T16:59:49.090 に答える