2015-12-07 30 views
29

Ho creato un UICollectionView, in modo da poter disporre le viste in colonne pulite. Mi piacerebbe che ci fosse un'unica colonna su dispositivi> 500 pixel di larghezza.UICollectionView - ridimensionamento delle celle sul dispositivo ruota - Swift

Per ottenere questo, ho creato questa funzione:

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

Questo funziona come previsto in primo carico, tuttavia quando ho ruotare il dispositivo, il calcolo non sempre avviene di nuovo, e la vista don sempre si ridisegna come previsto. Ecco il mio codice per quando il dispositivo viene ruotato:

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

sto assumendo ho dimenticato di ridisegnare qualcosa, ma non sono sicuro che cosa. Tutte le idee sono molto grate ricevute!

risposta

18

È possibile utilizzare viewWillLayoutSubviews. This question dovrebbe essere utile, ma questo viene chiamato in modo basso ogni volta che le viste del controller di visualizzazione stanno per impaginare le sue sottoview.

Quindi il codice sarà simile a questa:

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

utilizzando questo approccio si entra in un ciclo infinito. – valvoline

+3

Non sono sicuro che @valvoline sia corretto che ciò causerà un ciclo infinito, tuttavia potrebbe causare problemi di prestazioni poiché invalida il layout di collectionview molto più spesso del necessario. È molto meglio usare 'viewWillTransitionToSize'. – JosephH

+3

Questo codice causa un ciclo infinito. Non dovrebbe essere la risposta corretta. – Josh

13

ho la tendenza a utilizzare viewWillTransitionToSize con la stessa cosa e semplicemente fatto una chiamata invalidateLayout() in là.

22

Forse il modo più diritta per fare questo è di invalidateLayout durante la 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

avevo un compito di regolare le voci dimensione in UICollectionView sottoclasse. Il metodo migliore per questo è setFrame. Raccolta delle proprietà ViewFlowLayout Sono passato da ViewController (nel mio caso si trattava di un punto vendita dal layout di flusso predefinito).

metodo
// .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 potrebbe essere utilizzato come bene invece di 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

È possibile creare un contenuto maschera e spostarlo nella CollectionView. Al termine dell'animazione paesaggio/ritratto, è necessario rimuoverlo al più presto.

Ecco un esempio:

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