2012-11-25 53 views
98

我正在使用UICollectionViewUICollectionViewFlowLayout在不同設備方向上更改UICollectionViewCell大小

我設置每個小區的大小通過

collectionView:layout:sizeForItemAtIndexPath: 

當從縱向到橫向的切換,我想調整每個單元的尺寸,以完全貼合的CollectionView的大小,而不留下填充空間在細胞之間。

問題:

1)旋轉事件之後如何更改單元格的大小?

2)更好的是,如何使單元格始終適合屏幕的整個大小的佈局?

+0

followben的答案是目前公認的一個,但它有一些問題:它會拋出一個控制檯錯誤和動畫,新的大小將無法正常發生。看到我的答案正確的實施。 – memmons

+0

@ MichaelG.Emmons:如果集合視圖一次只顯示一個全尺寸的單元格,您的答案將會更好。在這種情況下,UIKit抱怨旋轉是有道理的,因爲在調用'didRotateFromInterfaceOrientation'之前它將查詢'sizeForItemAtIndexPath'。 但是,對於屏幕上具有多個單元格的集合視圖,在旋轉之前使佈局無效將在視圖旋轉之前導致大小令人討厭的可見跳轉。在這種情況下,我相信我的答案仍然是最正確的實施。 – followben

+0

@followben同意每個人在不同的使用案例中都有自己的問題。在這種情況下,OP表示「我想調整每個單元格的大小,使其完全符合CollectionView **的大小,這正是我答案中提出的解決方案。如果你可以在你的答案中包括我的解決方案,並記下哪種方法最適合我的條件。 – memmons

回答

198

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:會作廢的佈局和調整與動畫細胞(你可以通過零到兩個塊PARAMS如果你已經沒有多餘的調整來執行)。

2)不要對-collectionView:layout:sizeForItemAtIndexPath中的項目大小進行硬編碼,只需將collectionView的邊界的高度或寬度除以要放在屏幕上的單元格的數量即可。如果您的collectionView水平滾動,則使用高度;如果垂直滾動,則使用寬度。

+0

Fiveagle提出的解決方案也在工作,但這是我首選的解決方案。 – Fmessina

+0

如何在焦點位於另一個視圖控制器上時處理方向改變,然後焦點切換回原始視圖控制器。目前,我的細胞仍然保留由它們保留的方向確定的大小,但取決於新的方向。 –

+0

nm,我剛剛調用[self.collectionView performBatchUpdates:nil completion:nil]; viewDidAppear –

13

我解決了使用兩個UICollectionViewFlowLayout。一個用於肖像,另一個用於景觀。我把它們dinamically分配給我的CollectionView在-viewDidLoad

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]; 
    } 
} 
+0

謝謝!我會稍後嘗試您的解決方案,我會讓你知道。 – Fmessina

34

如果您不希望performBatchUpdates:completion:帶來額外的動畫,只需使用invalidateLayout即可強制collectionViewLayout重新加載。

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

有一個簡單的方法來設置集合視圖單元尺寸:

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

不知道它的動畫雖然。

+0

我不得不在viewWillLayout裏面用Hai Feng Kao的回答:http://stackoverflow.com/a/14776915/2298002 – greenhouse

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

這個很好用!在iOS 8中不推薦使用'willRotateToInterfaceOrientation',但'viewWillTransitionToSize'對此也適用。 – keegan3d

7

斯威夫特:集合視圖細胞是

我需要屏幕高度的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) 
} 
相關問題