異なるデバイスの向きでUICollectionViewCellサイズを変更する


100

UICollectionViewwith を使用していUICollectionViewFlowLayoutます。

を介して各セルのサイズを設定します

collectionView:layout:sizeForItemAtIndexPath:

ポートレートからランドスケープに切り替えるとき、各セルのサイズを調整して、セル間にパディングスペースを残さずに、CollectionViewのサイズに完全に合わせます。

質問:

1)回転イベント後にセルのサイズを変更するにはどうすればよいですか?

2)さらに良いことに、セルが常に画面全体のサイズに合うレイアウトを作成するにはどうすればよいですか?


followbenの答えは現在受け入れられていますが、いくつかの問題があります。コンソールエラーがスローされ、新しいサイズのアニメーションが正しく行われません。正しい実装については私の答えを参照してください。
memmons 2014年

@ MichaelG.Emmons:コレクションビューで一度に表示されるフルサイズのセルが1つだけの場合は、答えがうまく機能します。その場合、UIKitはをsizeForItemAtIndexPath呼び出す前にクエリを実行するため、ローテーションに対して不平を言うのは理にかなっていますdidRotateFromInterfaceOrientation。ただし、画面に複数のセルがあるコレクションビューの場合、回転前にレイアウトを無効にすると、ビューが回転する前にサイズが不快で目に見えるジャンプになります。その場合、私の答えはまだ最も正しい実装だと思います。
followben

@followbenそれぞれが異なるユースケースで問題を抱えていることに同意します。この場合でも、OPはI would like to adjust the size of each cell to **completely fit the size of the CollectionView**どちらが私の回答で提案されたソリューションであるかを正確に示します。あなたの答えに私の解決策を含めて、どのアプローチが私にとって十分な条件で最もうまく機能するかを書き留めることができれば。
memmons 2014年

回答:


200

1)複数のレイアウトオブジェクトを維持および交換できますが、より簡単な方法があります。以下をUICollectionViewControllerサブクラスに追加し、必要に応じてサイズを調整してください。

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout *)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{    
    // Adjust cell size for orientation
    if (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
        return CGSizeMake(170.f, 170.f);
    }
    return CGSizeMake(192.f, 192.f);
}

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [self.collectionView performBatchUpdates:nil completion:nil];
}

呼び出す-performBatchUpdates:completion:と、レイアウトが無効になり、アニメーションでセルのサイズが変更されます(実行する追加の調整がない場合は、両方のブロックパラメーターにnilを渡すことができます)。

2)でアイテムサイズをハードコーディングする代わりに-collectionView:layout:sizeForItemAtIndexPath、collectionViewの境界の高さまたは幅を、画面に表示するセルの数で除算します。collectionViewが水平方向にスクロールする場合は高さを使用し、垂直方向にスクロールする場合は幅を使用します。


3
なぜ電話しないの[self.collectionView.collectionViewLayout invalidateLayout];ですか?
user102008 2013年

7
@ user102008を呼び出すinvalidateLayoutと、セルが正しいサイズで再描画されますが-performBatchUpdates:completion:、変更がアニメーション化されるため、IMHOの見栄えがよくなります。
followben

4
私の場合、画面をスクロールするまで、コードはcollectionviewcellのサイズを変更しません。
newguy 2013

9
didRotateFromInterfaceOrientationiOSの8で非推奨
ヤーノシュ

8
iOS8では、を呼び出しcoordinator.animateAlongsideTransitionviewWillTransitionToSizeperformBatchUpdatesそのanimationブロック内で呼び出しています。これは素晴らしいアニメーション効果を与えます。
Mike Taverne、

33

によって追加のアニメーションが必要ない場合はperformBatchUpdates:completion:、を使用invalidateLayoutして、collectionViewLayoutを強制的にリロードします。

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    [self.collectionView.collectionViewLayout invalidateLayout];
}

13

2つのUICollectionViewFlowLayoutを使用して解決しました。1つはポートレート用、もう1つはランドスケープ用です。-viewDidLoadでそれらを私のcollectionViewに動的に割り当てます

self.portraitLayout = [[UICollectionViewFlowLayout alloc] init];
self.landscapeLayout = [[UICollectionViewFlowLayout alloc] init];

UIInterfaceOrientation orientationOnLunch = [[UIApplication sharedApplication] statusBarOrientation];

if (UIInterfaceOrientationIsPortrait(orientationOnLunch)) {
    [self.menuCollectionView setCollectionViewLayout:self.portraitLayout];
} else {
    [self.menuCollectionView setCollectionViewLayout:self.landscapeLayout];
}

次に、単にこのようにcollectionViewFlowLayoutDelgateメソッドを変更しました

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
    CGSize returnSize = CGSizeZero;

    if (collectionViewLayout == self.portraitLayout) {
        returnSize = CGSizeMake(230.0, 120.0);
    } else {
        returnSize = CGSizeMake(315.0, 120.0);
    }

    return returnSize;
}

最後にローテーションでレイアウトから別のレイアウトに切り替えます

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
    if (UIInterfaceOrientationIsPortrait(fromInterfaceOrientation)) {
        [self.menuCollectionView setCollectionViewLayout:self.landscapeLayout animated:YES];
    } else {
        [self.menuCollectionView setCollectionViewLayout:self.portraitLayout animated:YES];
    }
}

8

コレクションビューのセルサイズを設定する簡単な方法があります。

UICollectionViewFlowLayout *layout = (id) self.collectionView.collectionViewLayout;
layout.itemSize = CGSizeMake(cellSize, cellSize);

それがアニメート可能かどうかはわかりません。


:私は海風水花王の答えをviewWillLayoutSubviewsのこの内部を使用していたstackoverflow.com/a/14776915/2298002
温室

7

Swift:画面の高さのn%であるコレクションビューのセル

必要なのは、ビューの高さの特定の割合であり、デバイスの回転に合わせてサイズを変更するセルです。

上からの助けを借りて、ここに解決策があります

override func viewDidLoad() {
    super.viewDidLoad()
    automaticallyAdjustsScrollViewInsets = false
    // if inside nav controller set to true
}

override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) {
    collectionViewLayout.invalidateLayout()
}

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    return CGSize(width: 100, height: collectionView.frame.height * 0.9)
}

2

を使用している場合。フローレイアウトサブクラスで回転および調整するときに、ビューコントローラーで行うautolayout必要がinvalidate layoutありますoffset

だから、あなたのビューコントローラで-

override func willRotateToInterfaceOrientation(toInterfaceOrientation:     UIInterfaceOrientation, duration: NSTimeInterval) {
    self.galleryCollectionView.collectionViewLayout.invalidateLayout()
}

そしてあなたの中で FlowLayout Subclass

override func prepareLayout() {
    if self.collectionView!.indexPathsForVisibleItems().count > 0{
    var currentIndex : CGFloat!
    currentIndex = CGFloat((self.collectionView!.indexPathsForVisibleItems()[0] as! NSIndexPath).row)
    if let currentVal = currentIndex{
        self.collectionView!.contentOffset = CGPointMake(currentIndex * self.collectionView!.frame.width, self.collectionView!.contentOffset.y);
    }   
    }     
}

1
これはうまくいきます!willRotateToInterfaceOrientationiOS 8では非推奨ですがviewWillTransitionToSize、これでも同様に機能します。
keegan3d 2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.