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
の前に発生することを示しています。
また、明らかなことも検証しました。セルの高さをランドスケープ画面の高さよりも小さい固定サイズに設定した場合、苦情は発生しません。また、横向きから縦向きに回転するときに苦情は発生しません。
すべてが正常に実行され、正しくレンダリングされます。しかし、この苦情は私たちを心配させます。他にアイデアや解決策はありますか?
私は同じ警告を受けていました。 「reloadData」アプローチに満足せず、[self.collectionView.collectionViewFlowLayout invalidateLayout]
beforeコレクションビューのフレームを設定すると、警告が表示されず、予期した結果が得られました。
このロードされた、まだ受け入れられていないバービーに別のエビを投げないでください。
- (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つをオーバーライドします。私はどれを覚えていませんが。また、これが垂直レイアウトで機能するかどうかもわかりません。
に
[UIViewController willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration]
私は、[UICollectionViewLayout invalidateLayout]
そして、うまくいくようです。
解決しました。
FlowLayoutの高さをcollcetionView.frame.size.heightより小さくする必要があります。
[flowLayout setItemSize:CGSizeMake(width, height)];
collectionView.frame = CGRectMake(12, 380, 290, 80);
多くの解決策は、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()
}
これは私のために働く:(そしてそれがあなたにも役立つことを願っています!)
- (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);
}
同じ問題が発生し、修正されました。私の解決策はあなたが求めていた行に沿っており、既存の答えと一致しないため、ここに投稿しました。
#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];
}
これと同じ問題が発生しました。縦向きのときにコレクションビューが表示された場合、横向きに回転するとセルが消えます。これを修正するために、ここで他の回答の組み合わせを行いました。
ビュー(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;
これは私のためにそれを解決しました:
-(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
私の修正は、ナビゲーションバーを半透明にする必要があるため、IBのView Controllerの[スクロールビューのインセットの調整]をオフにするだけの簡単なものでした。
私は同じ問題に直面しました。ここに私がそれを解決した方法があります。それが役に立てば幸い
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:( NSTimeInterval)duration
{
[super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration];
[self.collectionView reloadData];
}
これを試して...
UICollectionViewFlowLayout *layout = (id) self.collectionView.collectionViewLayout;
layout.itemSize = CGSizeMake(0.1, 0.1);
それは私のために働いています。
IOS 7でこれらの警告を黙らせる解決策を見つけようとすることは、私にとって難しいことでした。私はUICollectionView
をサブクラス化することになり、次のコードを追加しました。
_- (void)setFrame:(CGRect)frame
{
if (!iOS8 && (frame.size.width != self.frame.size.width))
{
[self.collectionViewLayout invalidateLayout];
}
[super setFrame:frame];
}
_
一部のユーザーは、CGSizeEqualToSize()
を使用してサイズ全体のチェックを行いたい場合があります。
UICollectionViewのフレームのサイズを変更すると、同じ問題が発生しました。 FlowLayoutでデリゲートメソッドを使用してセルのサイズ(含まれるUICollectionViewのサイズに基づいて更新される)を返す場合、UICollectionViewのフレームのサイズを変更(小さく)するとエラーメッセージが表示されます。苦情を申し立てる前に、更新されたサイズ情報を代理人に尋ねたようには見えませんでした。最終的に、再描画時にデリゲートメソッドにサイズ情報を要求しますが、新しいフレームメソッドを割り当てたときに警告を発行します。警告を取り除くために、UICollectionViewFlowLayoutオブジェクトのitemSizeプロパティを明示的に設定しますbeforeフレームを新しい小さな値に設定します。私の状況は非常に単純なので、デリゲートメソッドに依存するのではなく、この時点でitemSizeの計算を行うことができます(コレクションビューのすべてのアイテムが同じサイズであるため)。デリゲートメソッドを実装したままでitemSizeプロパティを設定するだけでnotが問題を解決しました。デリゲートメソッドが実装されていることを検出した場合、itemSizeの値を無視したと思いますなぜそれを呼び出さないのですか?!)。うまくいけば、これが役立つ-おそらく、回転前にitemSizeを明示的に設定することもできます。
didRotateFromInterfaceOrientationの最後で試してください。
[self.collectionView setNeedsLayout]
うまくいかない場合は、didRotateFromInterfaceOrientationからwillRotateToInterfaceOrientationにすべてのものを移動してみてください
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);
}
UICollectionView
をサブクラス化し、setBounds:
をオーバーライドできます。 [super setBounds:]
を呼び出す前に、アイテムのサイズを新しい境界に調整できます。
_setBounds:
はスクロール中にも呼び出されるため、境界のサイズが変更されたかどうかを確認する必要があります。
注:私の場合、問題のpreferredContentSize
の-UIViewController
プロパティを設定していることがわかりました。これがあなたのケースであることがわかった場合、次のUICollectionViewDelegateFlowLayout
プロトコルのメソッドを処理する必要があるかもしれません。
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize size = collectionViewLayout.collectionView.bounds.size;
...
return size;
}
次のコードで修正されました:
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
return self.collectionView.frame.size;
}
警告を抑制し、(おそらく、わからない)サイズを返す前にパフォーマンスを改善するためだけに
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
view Controllerが回転中かどうかを確認し、CGSizeMake(0.1, 0.1)
のような比較的小さなサイズを返す場合
これは古い質問であることは知っていますが、同じ問題が発生し、それを解決するのに1時間かかりました。私の問題は、UICollectionView Flowレイアウトデリゲートが呼び出される直前にフレームサイズを設定している間、UICollectionViewのフレームサイズが常に間違っている(高さがコンテナーと一致しない)ように見えることでした。そこで、メソッドでUICollectionViewフレームサイズを再度設定します。
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
そして、それはトリックをしました。これで高さが正しく表示され、警告が消えました。