Изменение размера UICollectionViewCell на разных ориентациях устройства

Я использую UICollectionView с UICollectionViewFlowLayout.

Я устанавливаю размер каждой ячейки через

collectionView:layout:sizeForItemAtIndexPath:

При переключении с портретного на пейзаж я хотел бы настроить размер каждой ячейки, чтобы полностью соответствовать размеру CollectionView, не оставляя промежутка между ячейками.

Вопросы:

1) Как изменить размер ячейки после события вращения?

2) И еще лучше, как сделать макет, где ячейки всегда соответствуют всему размеру экрана?

Ответ 1

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 просто разделите высоту или ширину границ коллекцииView на количество ячеек, которые вы хотите поместить на экран. Используйте высоту, если ваша коллекцияView прокручивается по горизонтали или по ширине, если она прокручивается вертикально.

Ответ 2

Если вам не нужны дополнительные анимации, созданные performBatchUpdates:completion:, просто используйте invalidateLayout, чтобы принудительно перезагрузить collectionViewLayout.

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

Ответ 3

Я решил использовать два UICollectionViewFlowLayout. Один для портрета и один для пейзажа. Я назначаю их для моей коллекцииView динамически в -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];
    }
}

Ответ 4

Существует простой способ установить размер ячейки коллекции:

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

Не уверен, что он анимативен.

Ответ 5

Swift: коллекция View Cell, которая равна 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)
}

Ответ 6

Если вы используете 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);
    }   
    }     
}