2015-12-07 1 views
29

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

Для того, чтобы достичь этого, я создал эту функцию:

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { 
    let size = collectionView.frame.width 
    if (size > 500) { 
     return CGSize(width: (size/2) - 8, height: (size/2) - 8) 
    } 
    return CGSize(width: size, height: size) 
} 

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

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

Я предполагаю, что я забыл перерисовывать что-то, но я не уверен, что. Любые идеи очень благодарны!

ответ

18

Вы можете использовать viewWillLayoutSubviews. This question должен быть полезным, но это басически вызывается всякий раз, когда представления диспетчера представлений планируют разместить его вложенные объекты.

Так что ваш код будет выглядеть следующим образом:

override func viewWillLayoutSubviews() { 
    super.viewWillLayoutSubviews() 

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

    if UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) { 
    //here you can do the logic for the cell size if phone is in landscape 
    } else { 
    //logic if not landscape 
    } 

    flowLayout.invalidateLayout() 
} 
+6

, используя этот подход, вы будете входить в бесконечный цикл. – valvoline

+3

Я не уверен, что @valvoline правильно, что это вызовет бесконечный цикл - однако это может привести к проблемам с производительностью, поскольку это делает недействительным макет коллекции больше, чем это необходимо. Гораздо лучше использовать 'viewWillTransitionToSize'. – JosephH

+3

Этот код вызывает бесконечный цикл. Это не должен быть правильный ответ. – Josh

13

Я, как правило, использовать viewWillTransitionToSize с теми же вещами, и просто сделал звонок invalidateLayout() там.

22

Пожалуй, самый прямой способ сделать это состоит в invalidateLayout во время viewWillTransitionToSize:

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { 
    super.viewWillTransition(to: size, with: coordinator) 
    guard let flowLayout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout else { 
     return 
    } 
    flowLayout.invalidateLayout() 
} 
0

У меня была задача, чтобы отрегулировать размер пунктов в UICollectionView подкласса. Лучший способ для этого - setFrame. Свойство collectionViewFlowLayout Я перешел из ViewController (в моем случае это был выход из макета потока по умолчанию).

// .h 
@property (nonatomic, weak) UICollectionViewFlowLayout *collectionViewFlowLayout; 

// .m 
- (void)setFrame:(CGRect)frame { 
    if (!CGSizeEqualToSize(frame.size, self.frame.size)) { 
     collectionViewFlowLayout.itemSize = 
     CGSizeMake((UIDeviceOrientationIsLandscape(UIDevice.currentDevice.orientation) ? (frame.size.width - 10)/2 : frame.size.width), collectionViewFlowLayout.itemSize.height); 
    } 
    [super setFrame:frame]; 
} 
0

traitCollectionDidChange метод может быть использован, а вместо viewWillLayoutSubviews:

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { 
    super.traitCollectionDidChange(previousTraitCollection) 

    guard let previousTraitCollection = previousTraitCollection, traitCollection.verticalSizeClass != previousTraitCollection.verticalSizeClass || 
     traitCollection.horizontalSizeClass != previousTraitCollection.horizontalSizeClass else { 
      return 
    } 

    if traitCollection.horizontalSizeClass == .regular && traitCollection.verticalSizeClass == .regular { 
     // iPad portrait and landscape 
     // do something here... 
    } 
    if traitCollection.horizontalSizeClass == .compact && traitCollection.verticalSizeClass == .regular { 
     // iPhone portrait 
     // do something here... 
    } 
    if traitCollection.horizontalSizeClass == .regular && traitCollection.verticalSizeClass = .compact { 
     // iPhone landscape 
     // do something here... 
    } 
    collectionView?.collectionViewLayout.invalidateLayout() 
    collectionView?.reloadData() 
} 
0

Вы можете создать содержание маски и переместить его в CollectionView. После завершения анимации пейзаж/портрет вы должны удалить ее как можно скорее.

Вот пример:

@property (strong, nonatomic) UIImageView *maskImage; 

......... 

- (UIImageView *) imageForCellAtIndex: (NSInteger) index { 
    UICollectionView *collectionView = self.pagerView.test; 
    FSPagerViewCell *cell = nil; 
    NSArray *indexPaths = [collectionView indexPathsForVisibleItems]; 
    for (NSIndexPath *indexPath in indexPaths) { 
     if (indexPath.item == index) { 
      cell = (FSPagerViewCell *)[collectionView cellForItemAtIndexPath: indexPath]; 
      break; 
     } 
    } 
    if (cell) { 
     return cell.imageView; 
    } 
    return nil; 
} 


- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator 

{ 
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; 

    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context) 
    { 
     UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; 
     [self test_didRotateFromInterfaceOrientation: orientation]; 

     UIImageView *imageView = [self imageForCellAtIndex: self.pagerView.currentIndex]; 
     if (imageView) { 
       UIImageView *imageView = [self imageForCellAtIndex: self.pagerView.currentIndex]; 
       CGSize itemSize = self.pagerView.itemSize; 
       UIImageView *newImage = [[UIImageView alloc] initWithImage: imageView.image]; 
       [newImage setFrame: CGRectMake((_contentView.bounds.size.width - itemSize.width)/2.0f, 0, itemSize.width, itemSize.height)]; 
       newImage.contentMode = imageView.contentMode; 
       newImage.clipsToBounds = imageView.clipsToBounds; 
       newImage.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 
       [self.pagerView addSubview: newImage]; 

       self.maskImage = newImage; 
     } 

     [self.pagerView.test performBatchUpdates:^{ 
      [self.pagerView.test setCollectionViewLayout:self.pagerView.test.collectionViewLayout animated:YES]; 
     } completion:nil]; 
     // do whatever 
    } completion:^(id<UIViewControllerTransitionCoordinatorContext> context) 
    { 
     [self.maskImage removeFromSuperview]; 
    }]; 
} 
Смежные вопросы