web-dev-qa-db-ja.com

デバイスを横向きに回転させるときのUICollectionViewFlowLayoutサイズの警告

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の前に発生することを示しています。

また、明らかなことも検証しました。セルの高さをランドスケープ画面の高さよりも小さい固定サイズに設定した場合、苦情は発生しません。また、横向きから縦向きに回転するときに苦情は発生しません。

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

37
Mikel Nelson

私は同じ警告を受けていました。 「reloadData」アプローチに満足せず、[self.collectionView.collectionViewFlowLayout invalidateLayout]beforeコレクションビューのフレームを設定すると、警告が表示されず、予期した結果が得られました。

36
Chris Hinkle

このロードされた、まだ受け入れられていないバービーに別のエビを投げないでください。

- (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つをオーバーライドします。私はどれを覚えていませんが。また、これが垂直レイアウトで機能するかどうかもわかりません。

9
Josh Bruce

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

私は、[UICollectionViewLayout invalidateLayout]そして、うまくいくようです。

6
somebody

解決しました。

FlowLayoutの高さをcollcetionView.frame.size.heightより小さくする必要があります。

 [flowLayout setItemSize:CGSizeMake(width, height)];


 collectionView.frame = CGRectMake(12, 380, 290, 80);
4
Donny

多くの解決策は、invalidateLayoutwillAnimateRotationToInterfaceOrientationに追加することを提案していますが、これは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()
}
4
JosephH

これは私のために働く:(そしてそれがあなたにも役立つことを願っています!)

- (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); 
}
2
mayqiyue

同じ問題が発生し、修正されました。私の解決策はあなたが求めていた行に沿っており、既存の答えと一致しないため、ここに投稿しました。

#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];
}
2
lambmj

これと同じ問題が発生しました。縦向きのときにコレクションビューが表示された場合、横向きに回転するとセルが消えます。これを修正するために、ここで他の回答の組み合わせを行いました。

ビュー(UICollectionViewを含むビュー)をセットアップして、UIDeviceOrientationDidChangeNotification通知を受け取ります。その通知に応答するメソッドで、UICollectionViewフレームを調整した後、次のことを行いました。

- (void)orientationChanged:(NSNotification *)notification
{
    CGSize size = (CGSize){self.frame.size.width - 2*kContentMargin, self.frame.size.height - 2*kContentMargin};
    [self.collectionView.collectionViewLayout setItemSize:size];

    [self.collectionView.collectionViewLayout invalidateLayout];
    [self.collectionView reloadData];
}

UICollectionViewのフレームは、初期化時にresizingMaskがこれに設定されるため、回転時に自動的に設定されることに注意してください。

self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
2
Alfie Hanssen

これは私のためにそれを解決しました:

-(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
2
ullstrm

私の修正は、ナビゲーションバーを半透明にする必要があるため、IBのView Controllerの[スクロールビューのインセットの調整]をオフにするだけの簡単なものでした。

2

私は同じ問題に直面しました。ここに私がそれを解決した方法があります。それが役に立てば幸い

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(    NSTimeInterval)duration
{
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];

    [self.collectionView reloadData];
}
1
xun

これを試して...

UICollectionViewFlowLayout *layout = (id) self.collectionView.collectionViewLayout;

layout.itemSize = CGSizeMake(0.1, 0.1);

それは私のために働いています。

1

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

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

    [super setFrame:frame];
}
_

一部のユーザーは、CGSizeEqualToSize()を使用してサイズ全体のチェックを行いたい場合があります。

0
Ricky

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

0
Laura

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

[self.collectionView setNeedsLayout]

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

0
J.Williams

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);

}

0
MrJre

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

0
Eddie Gasparian

注:私の場合、問題のpreferredContentSizeの-​​UIViewControllerプロパティを設定していることがわかりました。これがあなたのケースであることがわかった場合、次のUICollectionViewDelegateFlowLayoutプロトコルのメソッドを処理する必要があるかもしれません。

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    CGSize size = collectionViewLayout.collectionView.bounds.size;
    ...
    return size;
}
0
Coach Roebuck

次のコードで修正されました:

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return self.collectionView.frame.size;
}
0
Obj-Swift

警告を抑制し、(おそらく、わからない)サイズを返す前にパフォーマンスを改善するためだけに

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

view Controllerが回転中かどうかを確認し、CGSizeMake(0.1, 0.1)のような比較的小さなサイズを返す場合

0

これは古い質問であることは知っていますが、同じ問題が発生し、それを解決するのに1時間かかりました。私の問題は、UICollectionView Flowレイアウトデリゲートが呼び出される直前にフレームサイズを設定している間、UICollectionViewのフレームサイズが常に間違っている(高さがコンテナーと一致しない)ように見えることでした。そこで、メソッドでUICollectionViewフレームサイズを再度設定します。

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

そして、それはトリックをしました。これで高さが正しく表示され、警告が消えました。

0
tyegah123