web-dev-qa-db-fra.com

Comment définir la taille d'une CollectionView en rotation

J'ai un viewcontroller avec 2 contrôleurs CollectionView.

J'aimerais que lors de la rotation, une seule des vues de collection soit redimensionnée à une taille personnalisée tandis que l'autre reste la même.

J'ai essayé d'utiliser:

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

Cependant, cela ne fait que modifier les deux vues de collection. Comment puis-je obtenir qu'il soit spécifique à une seule collection?

41
Robert Farr

Heres my 2 cents - parce que la taille de vos articles est statique, pourquoi ne pas définir la taille de l'article sur le collectionViewLayout?

Il sera plus rapide de le faire plutôt que de s'attendre à ce que la vue de collection appelle sa méthode déléguée pour chaque cellule.

viewWillLayoutSubviews peut être utilisé pour la détection de rotation sur les contrôleurs de vue. invalidateLayout peut être utilisé sur une présentation de vue de collection pour la forcer à préparer à nouveau la présentation, ce qui lui permet de positionner les éléments avec les nouvelles tailles dans ce cas.

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

modifier: mis à jour avec l'exemple Swift2.

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()
}
65
Oliver Atkinson

Avec la nouvelle API depuis iOS 8 j'utilise:

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

Objectif 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];
}
49
Tomasz Bąk

La réponse vérifiée n'est pas efficace

Le problème - L'invalidation de la mise en page dans viewWillLayoutSubviews () est un travail lourd. viewWillLayoutSubviews () est appelé plusieurs fois lorsqu'un ViewController est instancié.

Ma solution (Swift) - Intégrez votre manipulation de taille dans le 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's 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)
}
14
Neil Japhtha

Vous pouvez modifier votre instruction if. Vous devrez avoir une référence aux vues de collection

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

La question était de savoir comment séparer deux vues de collection dans sizeForItemAtIndexPath. Pourquoi pas quelque chose comme ça?

 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()
}
2
Illya Krit

J'ai résolu ce problème en vérifiant la rotation de l'appareil, puis en rechargeant la disposition. Vérifier la taille de l'écran et utiliser cette taille pour afficher ma cellule.

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

Ensuite, j'ai défini les cellules comme ceci

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