Farklı cihaz yönlerinde UICollectionViewCell boyutunu değiştirin


100

Bir UICollectionViewile kullanıyorum UICollectionViewFlowLayout.

Her hücrenin boyutunu

collectionView:layout:sizeForItemAtIndexPath:

Dikeyden yataya geçerken, hücreler arasında boşluk bırakmadan her hücrenin boyutunu CollectionView boyutuna tam olarak uyacak şekilde ayarlamak istiyorum.

Sorular:

1) Bir rotasyon olayından sonra bir hücrenin boyutu nasıl değiştirilir?

2) Ve daha da iyisi, hücrelerin her zaman ekranın tüm boyutuna sığdığı bir düzen nasıl yapılır?


followben'in cevabı şu anda kabul edildi, ancak bazı sorunları var: bir konsol hatası atacak ve yeni boyuta animasyon doğru şekilde gerçekleşmeyecek. Doğru uygulama için cevabıma bakın.
memmons

@ MichaelG.Emmons: Bir koleksiyon görünümünde aynı anda yalnızca tek bir tam boyutlu hücre görüntülendiğinde yanıtınız daha iyi sonuç verecektir. Bu durumda, UIKit'in, sizeForItemAtIndexPatharamadan önce sorgulayacağı için rotasyondan şikayet etmesi mantıklıdır didRotateFromInterfaceOrientation. Ancak, ekranda birden çok hücre bulunan bir koleksiyon görünümü için, döndürmeden önce düzeni geçersiz kılmak, görünüm dönmeden önce boyutta kötü, gözle görülür bir sıçramaya neden olur. Bu durumda, cevabımın hala en doğru uygulama olduğuna inanıyorum.
2014

@followben Her birinin farklı kullanım durumlarında kendi sorunları olduğunu kabul edin. Yine de bu durumda OP, cevabımda I would like to adjust the size of each cell to **completely fit the size of the CollectionView**tam olarak önerilen çözümün hangisi olduğunu belirtir . Cevabınıza benim çözümümü ekleyebilirseniz ve hangi yaklaşımın hangi koşullar altında en çok işe yaradığını not edin, bu benim için yeterli olacaktır.
memmons

Yanıtlar:


200

1) Birden çok yerleşim nesnesini koruyabilir ve değiştirebilirsin, ancak daha basit bir yolu var. Aşağıdakileri UICollectionViewControlleralt sınıfınıza eklemeniz ve boyutları gerektiği gibi ayarlamanız yeterlidir:

- (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];
}

Çağrı yapmak -performBatchUpdates:completion:düzeni geçersiz kılar ve hücreleri animasyonla yeniden boyutlandırır (gerçekleştirmek için fazladan ayarlamanız yoksa her iki blok parametresine de sıfır atabilirsiniz).

2) Öğe boyutlarını kodlamak yerine -collectionView:layout:sizeForItemAtIndexPath, collectionView sınırlarının yüksekliğini veya genişliğini ekrana sığdırmak istediğiniz hücre sayısına bölün. CollectionView yatay kaydırıyorsa yüksekliği, dikey kaydırıyorsa genişliği kullanın.


3
neden sadece aramıyorsun [self.collectionView.collectionViewLayout invalidateLayout];?
user102008

7
@ user102008 Arama invalidateLayout, hücreleri doğru boyutta yeniden çizecek, ancak -performBatchUpdates:completion:IMHO çok daha hoş görünen değişiklikleri canlandıracaktır.
followben

4
Benim durumumda kod, ekranı kaydırana kadar koleksiyon görüntüleme hücresini yeniden boyutlandırmıyor.
newguy

9
didRotateFromInterfaceOrientationiOS 8'de kullanımdan kaldırıldı
János

8
İOS8, ben arıyorum coordinator.animateAlongsideTransitioniçinde viewWillTransitionToSizeve çağırarak performBatchUpdatesonun içinde animationbloğun. Bu güzel bir animasyon efekti verir.
Mike Taverne

33

Ek animasyonların getirilmesini istemiyorsanız , collectionViewLayout'u yeniden yüklenmeye zorlamak için performBatchUpdates:completion:kullanın invalidateLayout.

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

13

İki UICollectionViewFlowLayout kullanarak çözdüm. Biri portre, diğeri manzara için. Onları -viewDidLoad içinde dinamik olarak görüntüle

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

Sonra collectionViewFlowLayoutDelgate Yöntemlerimi bu şekilde değiştirdim

- (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;
}

Son olarak rotasyonda bir düzenden diğerine geçiyorum

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

8

Koleksiyon görünümü hücre boyutunu ayarlamanın basit bir yolu vardır:

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

Yine de canlandırılabilir olup olmadığından emin değilim.


bunu görünüm içinde kullanmak zorunda kaldım WillLayoutSubviews with Hai Feng Kao'nun cevabı: stackoverflow.com/a/14776915/2298002
sera

7

Swift: Ekran yüksekliğinin% n'si olan Koleksiyon Görüntüleme Hücresi

İhtiyacım olan, görüntüleme yüksekliğinin belirli bir yüzdesi olan ve cihaz dönüşüyle ​​yeniden boyutlandırılacak bir hücreydi.

Yukarıdan yardım alarak, işte çözüm

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

Eğer kullanıyorsanız , akış düzeni alt sınıfınızı döndürürken ve ayarlarken autolayoutsadece invalidate layoutgörünüm denetleyicinizde yapmanız gerekir offset.

Yani, görünüm denetleyicinizde -

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

Ve senin içinde 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
Bu harika çalışıyor! willRotateToInterfaceOrientationiOS 8'de kullanımdan kaldırıldı, ancak viewWillTransitionToSizebunun için de iyi çalışıyor.
keegan3d
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.