Подтвердить что ты не робот

Как определить размер CollectionView при повороте

У меня есть viewcontroller с 2 контроллерами CollectionView.

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

Я попытался использовать:

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

Однако это просто изменяет оба коллекции. Как я могу получить конкретную информацию только для одной коллекции?

4b9b3361

Ответ 1

Вот мои 2 цента - потому что ваши размеры элементов статичны, почему вы не устанавливаете размер элемента на collectionViewLayout?

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

viewWillLayoutSubviews может использоваться для обнаружения вращения на контроллерах представления. invalidateLayout может использоваться на макете просмотра коллекции, чтобы заставить его снова подготовить макет, в результате чего он разместил элементы с новыми размерами в этом случае.

- (void)viewWillLayoutSubviews;
{
    [super viewWillLayoutSubviews];
    UICollectionViewFlowLayout *flowLayout = (id)self.firstCollectionView.collectionViewLayout;

    if (UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication.statusBarOrientation)) {
        flowLayout.itemSize = CGSizeMake(170.f, 170.f);
    } else {
        flowLayout.itemSize = CGSizeMake(192.f, 192.f);
    }

    [flowLayout invalidateLayout]; //force the elements to get laid out again with the new size
}

изменить: обновлено с помощью примера Swift2.0

override func viewWillLayoutSubviews() {
  super.viewWillLayoutSubviews()

  guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else {
    return
  }

  if UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) {
    flowLayout.itemSize = CGSize(width: 170, height: 170)
  } else {
    flowLayout.itemSize = CGSize(width: 192, height: 192)
  }

  flowLayout.invalidateLayout()
}

Ответ 2

С новым API с iOS 8 Я использую:

Swift 3:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    updateCollectionViewLayout(with: size)
}

private func updateCollectionViewLayout(with size: CGSize) {
    if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
        layout.itemSize = (size.width < size.height) ? itemSizeForPortraitMode : itemSizeForLandscapeMode
        layout.invalidateLayout()
    }
}

Objective-C:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
        [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
        [self updateCollectionViewLayoutWithSize:size];
}

- (void)updateCollectionViewLayoutWithSize:(CGSize)size {
        UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
        layout.itemSize = (size.width < size.height) ? itemSizeForPortraitMode : itemSizeForLandscapeMode;
        [layout invalidateLayout];
}

Ответ 3

Проверенный ответ неэффективен

Проблема. Недействительность макета в viewWillLayoutSubviews() - это тяжелая работа. viewWillLayoutSubviews() вызывается несколько раз при создании экземпляра ViewController.

Мое решение (Swift). Внедрите свои манипуляции с размерами в UICollectionViewDelegateFlowLayout.

// Keep a local property that we will always update with the latest 
// view size.
var updatedSize: CGSize!

// Use the UICollectionViewDelegateFlowLayout to set the size of our        
// cells.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    // We will set our updateSize value if it nil.
    if updateSize == nil {
        // At this point, the correct ViewController frame is set.
        self.updateSize = self.view.frame.size
    }

    // If your collectionView is full screen, you can use the 
    // frame size to judge whether you're in landscape.
    if self.updateSize.width > self.updateSize.height {
        return CGSize(width: 170, 170)
    } else {
        return CGSize(width: 192, 192)
    }
}

// Finally, update the size of the updateSize property, every time 
// viewWillTransitionToSize is called.  Then performBatchUpdates to
// adjust our layout.
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    self.updateSize = size
    self.collectionView!.performBatchUpdates(nil, completion: nil)
}

Ответ 4

Вы можете изменить оператор if. Вам нужно будет иметь ссылку на представления коллекции

if (UIDeviceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]) && collectionView == self.firstCollectionView) {
   return CGSizeMake(170.f, 170.f);
}

Ответ 5

Вопрос состоял в том, как разделить два вида коллекции в sizeForItemAtIndexPath. Почему просто не что-то подобное?

 func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {

    if collectionView == firstCollectionView{

            return CGSize(width: self.frame.width/3, height: 40)
       }


    else if collectionView == secondCollectionView{

        return CGSize(width: self.frame.width, height: self.frame.height-2)
    }

    abort()
}

Ответ 6

Я решил эту проблему, проверив вращение устройства, а затем перезагрузив макет. Проверка размера экрана и использование этого размера для отображения моей ячейки.

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    //get new width of the screen
    screenRect = [[UIScreen mainScreen] bounds];
    screenWidth = screenRect.size.width;

    //if landscape mode
    if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
    {
        screenDivide = 5;
    }
    else
    {
        screenDivide = 3;
    }

    //reload the collectionview layout after rotating
    UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionView.collectionViewLayout;
    [layout invalidateLayout];
}

Затем я определил ячейки, подобные этой

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    screenRect = [[UIScreen mainScreen] bounds];
    screenWidth = screenRect.size.width;

    CGSize elementSize = CGSizeMake(screenWidth/screenDivide, 100);
    return elementSize;
}

Ответ 7

Я справился с этим, обнаружив изменение ориентации в методе setBounds:. Мы подклассифицируем UICollectionView и переопределяем метод setBounds: (см. Ниже). В flowLayoutForGallerySize мы создаем новый UICollectionViewFlowLayout с различным интервалом и itemSize в зависимости от размера представления коллекции.

- (void)setBounds:(CGRect)bounds
{
    // detect orientation changes and update itemSize in the flow layout
    CGSize oldSize = self.bounds.size;

    [super setBounds:bounds];

    BOOL wasLandscape = (oldSize.width > oldSize.height);
    BOOL nowLandscape = (bounds.size.width > bounds.size.height);

    if (wasLandscape != nowLandscape) {
        // create a new flow layout object for the new gallery size
        self.flowLayout = [self flowLayoutForGallerySize:bounds.size];

        // change to the new flow layout
        [self setCollectionViewLayout:self.flowLayout animated:NO];

        DLog(@"orientation change to %@", NSStringFromCGSize(bounds.size));
    }
}