Ubah ukuran UICollectionViewCell pada orientasi perangkat yang berbeda

100

Saya menggunakan UICollectionViewdengan UICollectionViewFlowLayout.

Saya mengatur ukuran setiap sel melalui

collectionView:layout:sizeForItemAtIndexPath:

Saat beralih dari potret ke lanskap, saya ingin menyesuaikan ukuran setiap sel agar benar-benar sesuai dengan ukuran CollectionView, tanpa meninggalkan ruang bantalan antar sel.

Pertanyaan:

1) Bagaimana cara mengubah ukuran sel setelah acara rotasi?

2) Dan, lebih baik lagi, bagaimana membuat tata letak di mana sel-sel selalu sesuai dengan seluruh ukuran layar?

Fmessina
sumber
Jawaban followben saat ini diterima, tetapi memiliki beberapa masalah: itu akan menimbulkan kesalahan konsol dan animasi ke ukuran baru tidak akan terjadi dengan benar. Lihat jawaban saya untuk implementasi yang benar.
memmons
@ MichaelG.Emmons: jawaban Anda akan berfungsi lebih baik di mana tampilan koleksi hanya menampilkan satu sel berukuran penuh pada satu waktu. Dalam hal ini, masuk akal jika UIKit mengeluh tentang rotasi karena akan membuat kueri sizeForItemAtIndexPathsebelum memanggil didRotateFromInterfaceOrientation. Namun, untuk tampilan koleksi dengan beberapa sel di layar, membatalkan tata letak sebelum rotasi menyebabkan lompatan ukuran yang terlihat dan tidak menyenangkan sebelum tampilan berputar. Dalam hal ini, saya yakin jawaban saya masih merupakan implementasi yang paling benar.
followben
@followben Setuju bahwa masing-masing memiliki masalah dalam kasus penggunaan yang berbeda. Namun dalam kasus ini, OP menunjukkan I would like to adjust the size of each cell to **completely fit the size of the CollectionView**solusi yang tepat yang diusulkan dalam jawaban saya. Jika Anda dapat memasukkan solusi saya dalam jawaban Anda dan mencatat pendekatan mana yang paling berhasil dalam kondisi apa yang cukup baik untuk saya.
memmons

Jawaban:

200

1) Anda dapat memelihara dan menukar beberapa objek tata letak, tetapi ada cara yang lebih sederhana. Cukup tambahkan yang berikut ini ke UICollectionViewControllersubkelas Anda dan sesuaikan ukurannya sesuai kebutuhan:

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

Memanggil -performBatchUpdates:completion:akan membatalkan tata letak dan mengubah ukuran sel dengan animasi (Anda bisa meneruskan nil ke kedua parameter blok jika Anda tidak memiliki penyesuaian tambahan untuk dilakukan).

2) Daripada melakukan hardcode ukuran item -collectionView:layout:sizeForItemAtIndexPath, cukup bagi tinggi atau lebar batas collectionView dengan jumlah sel yang ingin Anda muat di layar. Gunakan tinggi jika collectionView Anda menggulir secara horizontal atau lebarnya jika menggulir secara vertikal.

followben
sumber
3
kenapa tidak menelepon saja [self.collectionView.collectionViewLayout invalidateLayout];?
user102008
7
@ user102008 Memanggil invalidateLayoutakan menggambar ulang sel dengan ukuran yang benar, tetapi -performBatchUpdates:completion:akan menghidupkan perubahan, yang IMHO terlihat jauh lebih bagus.
followben
4
Dalam kasus saya, kode tidak mengubah ukuran collectionviewcell sampai saya menggulir layar.
newguy
9
didRotateFromInterfaceOrientationtidak digunakan lagi di iOS 8
János
8
Pada iOS8, aku menelepon coordinator.animateAlongsideTransitiondi viewWillTransitionToSize, dan memanggil performBatchUpdatesdalam nya animationblok. Ini memberikan efek animasi yang bagus.
Mike Taverne
33

Jika Anda tidak ingin animasi tambahan dibawa oleh performBatchUpdates:completion:, cukup gunakan invalidateLayoutuntuk memaksa collectionViewLayout memuat ulang.

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    [self.collectionView.collectionViewLayout invalidateLayout];
}
Hai Feng Kao
sumber
13

Saya memecahkan menggunakan dua UICollectionViewFlowLayout. Satu untuk potret dan satu untuk lanskap. Saya menetapkannya ke collectionView saya secara dinamis di -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];
}

Kemudian saya hanya memodifikasi Metode collectionViewFlowLayoutDelgate saya seperti ini

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

Terakhir saya beralih dari tata letak ke tata letak lainnya pada rotasi

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

Ada cara sederhana untuk menyetel ukuran sel tampilan koleksi:

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

Tidak yakin apakah itu bisa dianimasikan.

Dannie P.
sumber
saya harus menggunakan ini di dalam viewWillLayoutSubviews dengan jawaban Hai Feng Kao: stackoverflow.com/a/14776915/2298002
rumah kaca
7

Swift: Sel Tampilan Koleksi yang n% dari tinggi layar

Yang saya butuhkan adalah sel dengan persentase tertentu dari tinggi tampilan, dan akan diubah ukurannya dengan rotasi perangkat.

Dengan bantuan dari atas, inilah solusinya

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)
}
DogCoffee
sumber
2

Jika Anda menggunakan autolayout. Anda hanya perlu invalidate layoutdi pengontrol tampilan saat memutar dan menyesuaikan offsetdi subkelas tata letak aliran Anda.

Jadi, Dalam pengontrol tampilan Anda -

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

Dan di 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);
    }   
    }     
}
toofani
sumber
1
Ini bekerja dengan baik! willRotateToInterfaceOrientationsudah tidak digunakan lagi di iOS 8 tetapi juga viewWillTransitionToSizeberfungsi untuk ini.
keegan3d